OpenCores
URL https://opencores.org/ocsvn/System09/System09/trunk

Subversion Repositories System09

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /System09
    from Rev 129 to Rev 130
    Reverse comparison

Rev 129 → Rev 130

/trunk/rtl/VHDL/cpu09l.vhd
199,14 → 199,57
-- Enumerated separate states for MASKI and MASKIF states
-- Removed code on BSR/JSR in fetch cycle
--
-- Version 1.10 - 8th October 2011 - John Kent
-- Version 1.20 - 8th October 2011 - John Kent
-- added fetch output which should go high during the fetch cycle
--
-- Version 1.11 - 8th October 2011 - John Kent
-- Version 1.21 - 8th October 2011 - John Kent
-- added Last Instruction Cycle signal
-- replaced fetch with ifetch (instruction fetch) signal
-- added ba & bs (bus available & bus status) signals
--
-- Version 1.22 - 2011-10-29 John Kent
-- The halt state isn't correct.
-- The halt state is entered into from the fetch_state
-- It returned to the fetch state which may re-run an execute cycle
-- on the accumulator and it won't necessarily be the last instruction cycle
-- I've changed the halt state to return to the decode1_state
--
-- Version 1.23 - 2011-10-30 John Kent
-- sample halt in the change_state process if lic is high (last instruction cycle)
--
-- Version 1.24 - 2011-11-01 John Kent
-- Handle interrupts in change_state process
-- Sample interrupt inputs on last instruction cycle
-- Remove iv_ctrl and implement iv (interrupt vector) in change_state process.
-- Generate fic (first instruction cycle) from lic (last instruction cycle)
-- and use it to complete the dual operand execute cycle before servicing
-- halt or interrupts requests.
-- rename lic to lic_out on the entity declaration so that lic can be tested internally.
-- add int_firq1_state and int_nmirq1_state to allow for the dual operand execute cycle
-- integrated nmi_ctrl into change_state process
-- Reduces the microcode state stack to one entry (saved_state)
-- imm16_state jumps directly to the fetch_state
-- pull_return_lo states jumps directly to the fetch_state
-- duplicate andcc_state as cwai_state
-- rename exg1_state as exg2 state and duplicate tfr_state as exg1_state
--
-- Version 1.25 - 2011-11-27 John Kent
-- Changed the microcode for saving registers on an interrupt into a microcode subroutine.
-- Removed SWI servicing from the change state process and made SWI, SWI2 & SWI3
-- call the interrupt microcode subroutine.
-- Added additional states for nmi, and irq for interrupt servicing.
-- Added additional states for nmi/irq, firq, and swi interrupts to mask I & F flags.
--
-- Version 1.26 - 2013-03-18 John Kent
-- pre-initialized cond_true variable to true in state sequencer
-- re-arranged change_state process slightly
--
-- Version 1.27 - 2015-05-30 John Kent
-- Added test in state machine for masked IRQ and FIRQ in Sync_state.
--
-- Version 1.28 - 2015-05-30 John Kent.
-- Moved IRQ and FIRQ test from state machine to the state sequencer Sync_state.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
216,8 → 259,9
clk : in std_logic; -- E clock input (falling edge)
rst : in std_logic; -- reset input (active high)
vma : out std_logic; -- valid memory address (active high)
lic : out std_logic; -- last instruction cycle (active high)
lic_out : out std_logic; -- last instruction cycle (active high)
ifetch : out std_logic; -- instruction fetch cycle (active high)
opfetch : out std_logic; -- opcode fetch (active high)
ba : out std_logic; -- bus available (high on sync wait or DMA grant)
bs : out std_logic; -- bus status (high on interrupt or reset vector fetch or DMA grant)
addr : out std_logic_vector(15 downto 0); -- address bus output
258,7 → 302,7
type state_type is (-- Start off in Reset
reset_state,
-- Fetch Interrupt Vectors (including reset)
vect_lo_state, vect_hi_state,
vect_lo_state, vect_hi_state, vect_idle_state,
-- Fetch Instruction Cycle
fetch_state,
-- Decode Instruction Cycles
279,10 → 323,11
dual_op_read8_state, dual_op_read16_state, dual_op_read16_2_state,
dual_op_write8_state, dual_op_write16_state,
--
sync_state, halt_state, error_state,
sync_state, halt_state, cwai_state,
--
andcc_state, orcc_state,
tfr_state, exg_state, exg1_state,
tfr_state,
exg_state, exg1_state, exg2_state,
lea_state,
-- Multiplication
mul_state, mulea_state, muld_state,
295,7 → 340,9
push_return_hi_state, push_return_lo_state,
pull_return_hi_state, pull_return_lo_state,
-- Interrupt cycles
int_nmiirq_state, int_firq_state,
int_nmi_state, int_nmi1_state,
int_irq_state, int_irq1_state,
int_firq_state, int_firq1_state,
int_entire_state, int_fast_state,
int_pcl_state, int_pch_state,
int_upl_state, int_uph_state,
305,7 → 352,7
int_accb_state, int_acca_state,
int_cc_state,
int_cwai_state,
int_maski_state, int_maskif_state,
int_nmimask_state, int_firqmask_state, int_swimask_state, int_irqmask_state,
-- Return From Interrupt
rti_cc_state, rti_entire_state,
rti_acca_state, rti_accb_state,
351,8 → 398,8
pulu_spl_state, pulu_sph_state,
pulu_pcl_state, pulu_pch_state );
 
type stack_type is array(2 downto 0) of state_type;
type st_type is (idle_st, push_st, pull_st );
type st_type is (reset_st, push_st, idle_st );
type iv_type is (latch_iv, swi3_iv, swi2_iv, firq_iv, irq_iv, swi_iv, nmi_iv, reset_iv);
type addr_type is (idle_ad, fetch_ad, read_ad, write_ad, pushu_ad, pullu_ad, pushs_ad, pulls_ad, int_hi_ad, int_lo_ad );
type dout_type is (cc_dout, acca_dout, accb_dout, dp_dout,
ix_lo_dout, ix_hi_dout, iy_lo_dout, iy_hi_dout,
371,8 → 418,6
type pc_type is (reset_pc, latch_pc, load_pc, pull_lo_pc, pull_hi_pc, incr_pc );
type md_type is (reset_md, latch_md, load_md, fetch_first_md, fetch_next_md, shiftl_md );
type ea_type is (reset_ea, latch_ea, load_ea, fetch_first_ea, fetch_next_ea );
type iv_type is (latch_iv, reset_iv, nmi_iv, irq_iv, firq_iv, swi_iv, swi2_iv, swi3_iv, resv_iv);
type nmi_type is (reset_nmi, set_nmi, latch_nmi );
type left_type is (cc_left, acca_left, accb_left, dp_left,
ix_left, iy_left, up_left, sp_left,
accd_left, md_left, pc_left, ea_left );
410,13 → 455,15
signal nmi_req: std_logic;
signal nmi_ack: std_logic;
signal nmi_enable: std_logic;
signal fic: std_logic; -- first instruction cycle
signal lic: std_logic; -- last instruction cycle
 
signal state: state_type;
signal next_state: state_type;
signal return_state: state_type;
signal saved_state: state_type;
signal return_state: state_type;
signal state_stack: stack_type;
signal st_ctrl: st_type;
signal iv_ctrl: iv_type;
signal pc_ctrl: pc_type;
signal ea_ctrl: ea_type;
signal op_ctrl: op_type;
430,13 → 477,11
signal dp_ctrl: dp_type;
signal sp_ctrl: sp_type;
signal up_ctrl: up_type;
signal iv_ctrl: iv_type;
signal left_ctrl: left_type;
signal right_ctrl: right_type;
signal alu_ctrl: alu_type;
signal addr_ctrl: addr_type;
signal dout_ctrl: dout_type;
signal nmi_ctrl: nmi_type;
 
 
begin
448,39 → 493,56
----------------------------------
--state_stack_proc: process( clk, hold, state_stack, st_ctrl,
-- return_state, fetch_state )
state_stack_proc: process( clk, state_stack )
state_stack_proc: process( clk, st_ctrl, return_state )
begin
if clk'event and clk = '0' then
if hold= '1' then
state_stack(0) <= state_stack(0);
state_stack(1) <= state_stack(1);
state_stack(2) <= state_stack(2);
else
if hold = '0' then
case st_ctrl is
when idle_st =>
state_stack(0) <= state_stack(0);
state_stack(1) <= state_stack(1);
state_stack(2) <= state_stack(2);
when reset_st =>
saved_state <= fetch_state;
when push_st =>
state_stack(0) <= return_state;
state_stack(1) <= state_stack(0);
state_stack(2) <= state_stack(1);
when pull_st =>
state_stack(0) <= state_stack(1);
state_stack(1) <= state_stack(2);
state_stack(2) <= fetch_state;
saved_state <= return_state;
when others =>
state_stack(0) <= state_stack(0);
state_stack(1) <= state_stack(1);
state_stack(2) <= state_stack(2);
null;
end case;
end if;
end if;
saved_state <= state_stack(0);
end process;
 
----------------------------------
--
-- Interrupt Vector control
--
----------------------------------
--
int_vec_proc: process( clk, iv_ctrl )
begin
if clk'event and clk = '0' then
if hold = '0' then
case iv_ctrl is
when reset_iv =>
iv <= RST_VEC;
when nmi_iv =>
iv <= NMI_VEC;
when swi_iv =>
iv <= SWI_VEC;
when irq_iv =>
iv <= IRQ_VEC;
when firq_iv =>
iv <= FIRQ_VEC;
when swi2_iv =>
iv <= SWI2_VEC;
when swi3_iv =>
iv <= SWI3_VEC;
when others =>
null;
end case;
end if; -- hold
end if; -- clk
end process;
----------------------------------
--
-- Program Counter Control
--
----------------------------------
489,12 → 551,10
pc_reg: process( clk )
begin
if clk'event and clk = '0' then
if hold= '1' then
pc <= pc;
else
if hold = '0' then
case pc_ctrl is
when reset_pc =>
pc <= "0000000000000000";
pc <= (others=>'0');
when load_pc =>
pc <= out_alu(15 downto 0);
when pull_lo_pc =>
504,8 → 564,7
when incr_pc =>
pc <= pc + 1;
when others =>
-- when latch_pc =>
pc <= pc;
null;
end case;
end if;
end if;
522,12 → 581,10
begin
 
if clk'event and clk = '0' then
if hold= '1' then
ea <= ea;
else
if hold= '0' then
case ea_ctrl is
when reset_ea =>
ea <= "0000000000000000";
ea <= (others=>'0');
when fetch_first_ea =>
ea(7 downto 0) <= data_in;
ea(15 downto 8) <= dp;
537,8 → 594,7
when load_ea =>
ea <= out_alu(15 downto 0);
when others =>
-- when latch_ea =>
ea <= ea;
null;
end case;
end if;
end if;
553,12 → 609,10
acca_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold= '1' then
acca <= acca;
else
if hold = '0' then
case acca_ctrl is
when reset_acca =>
acca <= "00000000";
acca <= (others=>'0');
when load_acca =>
acca <= out_alu(7 downto 0);
when load_hi_acca =>
566,8 → 620,7
when pull_acca =>
acca <= data_in;
when others =>
-- when latch_acca =>
acca <= acca;
null;
end case;
end if;
end if;
582,19 → 635,16
accb_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold= '1' then
accb <= accb;
else
if hold = '0' then
case accb_ctrl is
when reset_accb =>
accb <= "00000000";
accb <= (others=>'0');
when load_accb =>
accb <= out_alu(7 downto 0);
when pull_accb =>
accb <= data_in;
when others =>
-- when latch_accb =>
accb <= accb;
null;
end case;
end if;
end if;
609,12 → 659,10
ix_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold= '1' then
xreg <= xreg;
else
if hold = '0' then
case ix_ctrl is
when reset_ix =>
xreg <= "0000000000000000";
xreg <= (others=>'0');
when load_ix =>
xreg <= out_alu(15 downto 0);
when pull_hi_ix =>
622,8 → 670,7
when pull_lo_ix =>
xreg(7 downto 0) <= data_in;
when others =>
-- when latch_ix =>
xreg <= xreg;
null;
end case;
end if;
end if;
638,12 → 685,10
iy_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold= '1' then
yreg <= yreg;
else
if hold = '0' then
case iy_ctrl is
when reset_iy =>
yreg <= "0000000000000000";
yreg <= (others=>'0');
when load_iy =>
yreg <= out_alu(15 downto 0);
when pull_hi_iy =>
651,8 → 696,7
when pull_lo_iy =>
yreg(7 downto 0) <= data_in;
when others =>
-- when latch_iy =>
yreg <= yreg;
null;
end case;
end if;
end if;
667,13 → 711,10
sp_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold= '1' then
sp <= sp;
nmi_enable <= nmi_enable;
else
if hold = '0' then
case sp_ctrl is
when reset_sp =>
sp <= "0000000000000000";
sp <= (others=>'0');
nmi_enable <= '0';
when load_sp =>
sp <= out_alu(15 downto 0);
680,14 → 721,11
nmi_enable <= '1';
when pull_hi_sp =>
sp(15 downto 8) <= data_in;
nmi_enable <= nmi_enable;
when pull_lo_sp =>
sp(7 downto 0) <= data_in;
nmi_enable <= '1';
when others =>
-- when latch_sp =>
sp <= sp;
nmi_enable <= nmi_enable;
null;
end case;
end if;
end if;
702,12 → 740,10
up_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold= '1' then
up <= up;
else
if hold = '0' then
case up_ctrl is
when reset_up =>
up <= "0000000000000000";
up <= (others=>'0');
when load_up =>
up <= out_alu(15 downto 0);
when pull_hi_up =>
715,8 → 751,7
when pull_lo_up =>
up(7 downto 0) <= data_in;
when others =>
-- when latch_up =>
up <= up;
null;
end case;
end if;
end if;
731,12 → 766,10
md_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold= '1' then
md <= md;
else
if hold = '0' then
case md_ctrl is
when reset_md =>
md <= "0000000000000000";
md <= (others=>'0');
when load_md =>
md <= out_alu(15 downto 0);
when fetch_first_md => -- sign extend md for branches
750,8 → 783,7
md(15 downto 1) <= md(14 downto 0);
md(0) <= '0';
when others =>
-- when latch_md =>
md <= md;
null;
end case;
end if;
end if;
768,9 → 800,7
cc_reg: process( clk )
begin
if clk'event and clk = '0' then
if hold= '1' then
cc <= cc;
else
if hold = '0' then
case cc_ctrl is
when reset_cc =>
cc <= "11010000"; -- set EBIT, FBIT & IBIT
779,8 → 809,7
when pull_cc =>
cc <= data_in;
when others =>
-- when latch_cc =>
cc <= cc;
null;
end case;
end if;
end if;
796,62 → 825,22
dp_reg: process( clk )
begin
if clk'event and clk = '0' then
if hold= '1' then
dp <= dp;
else
if hold = '0' then
case dp_ctrl is
when reset_dp =>
dp <= "00000000";
dp <= (others=>'0');
when load_dp =>
dp <= out_alu(7 downto 0);
when pull_dp =>
dp <= data_in;
when others =>
-- when latch_dp =>
dp <= dp;
null;
end case;
end if;
end if;
end process;
 
----------------------------------
--
-- interrupt vector
--
----------------------------------
 
--iv_mux: process( clk, iv_ctrl, hold, iv )
iv_mux: process( clk )
begin
if clk'event and clk = '0' then
if hold= '1' then
iv <= iv;
else
case iv_ctrl is
when reset_iv =>
iv <= RST_VEC;
when nmi_iv =>
iv <= NMI_VEC;
when swi_iv =>
iv <= SWI_VEC;
when irq_iv =>
iv <= IRQ_VEC;
when firq_iv =>
iv <= FIRQ_VEC;
when swi2_iv =>
iv <= SWI2_VEC;
when swi3_iv =>
iv <= SWI3_VEC;
when resv_iv =>
iv <= RESV_VEC;
when others =>
iv <= iv;
end case;
end if;
end if;
end process;
 
 
----------------------------------
--
-- op code register
862,9 → 851,7
op_reg: process( clk )
begin
if clk'event and clk = '0' then
if hold= '1' then
op_code <= op_code;
else
if hold = '0' then
case op_ctrl is
when reset_op =>
op_code <= "00010010";
871,8 → 858,7
when fetch_op =>
op_code <= data_in;
when others =>
-- when latch_op =>
op_code <= op_code;
null;
end case;
end if;
end if;
889,17 → 875,14
pre_reg: process( clk )
begin
if clk'event and clk = '0' then
if hold= '1' then
pre_code <= pre_code;
else
if hold = '0' then
case pre_ctrl is
when reset_pre =>
pre_code <= "00000000";
pre_code <= (others=>'0');
when fetch_pre =>
pre_code <= data_in;
when others =>
-- when latch_pre =>
pre_code <= pre_code;
null;
end case;
end if;
end if;
916,46 → 899,60
begin
if clk'event and clk = '0' then
if rst = '1' then
state <= reset_state;
else
if hold = '1' then
state <= state;
else
state <= next_state;
end if;
end if;
end if;
fic <= '0';
nmi_ack <= '0';
state <= reset_state;
elsif hold = '0' then
fic <= lic;
--
-- nmi request is not cleared until nmi input goes low
--
if (nmi_req = '0') and (nmi_ack='1') then
nmi_ack <= '0';
end if;
if (nmi_req = '1') and (nmi_ack = '0') and (state = int_nmimask_state) then
nmi_ack <= '1';
end if;
 
if lic = '1' then
if halt = '1' then
state <= halt_state;
-- service non maskable interrupts
elsif (nmi_req = '1') and (nmi_ack = '0') then
state <= int_nmi_state;
--
-- FIRQ & IRQ are level sensitive
--
elsif (firq = '1') and (cc(FBIT) = '0') then
state <= int_firq_state;
 
elsif (irq = '1') and (cc(IBIT) = '0') then
state <= int_irq_state;
--
-- Version 1.27 2015-05-30
-- Exit sync_state on masked interrupt.
--
-- Version 1.28 2015-05-30
-- Move this code to the state sequencer
-- near line 5566.
--
-- elsif (state = sync_state) and ((firq = '1') or (irq = '1'))then
-- state <= fetch_state;
--
else
state <= next_state;
end if; -- halt, nmi, firq, irq
else
state <= next_state;
end if; -- lic
end if; -- reset/hold
end if; -- clk
end process;
-- output
------------------------------------
--
-- Nmi register
--
------------------------------------
 
--nmi_reg: process( clk, nmi_ctrl, hold, nmi_ack )
nmi_reg: process( clk )
begin
if clk'event and clk='0' then
if hold = '1' then
nmi_ack <= nmi_ack;
else
case nmi_ctrl is
when set_nmi =>
nmi_ack <= '1';
when reset_nmi =>
nmi_ack <= '0';
when others =>
-- when latch_nmi =>
nmi_ack <= nmi_ack;
end case;
end if;
end if;
end process;
 
------------------------------------
--
-- Detect Edge of NMI interrupt
--
------------------------------------
987,33 → 984,39
begin
ifetch <= '0';
vma <= '1';
rw <= '1';
addr <= "1111111111111111";
case addr_ctrl is
when fetch_ad =>
addr <= pc;
rw <= '1';
ifetch <= '1';
when read_ad =>
addr <= ea;
addr <= ea;
rw <= '1';
when write_ad =>
addr <= ea;
rw <= '0';
addr <= ea;
rw <= '0';
when pushs_ad =>
addr <= sp;
rw <= '0';
addr <= sp;
rw <= '0';
when pulls_ad =>
addr <= sp;
addr <= sp;
rw <= '1';
when pushu_ad =>
addr <= up;
rw <= '0';
addr <= up;
rw <= '0';
when pullu_ad =>
addr <= up;
addr <= up;
rw <= '1';
when int_hi_ad =>
addr <= "111111111111" & iv & "0";
addr <= "111111111111" & iv & "0";
rw <= '1';
when int_lo_ad =>
addr <= "111111111111" & iv & "1";
addr <= "111111111111" & iv & "1";
rw <= '1';
when others =>
vma <= '0';
addr <= "1111111111111111";
rw <= '1';
vma <= '0';
end case;
end process;
 
1057,8 → 1060,6
data_out <= pc(7 downto 0);
when pc_hi_dout => -- high order pc
data_out <= pc(15 downto 8);
when others =>
data_out <= "00000000";
end case;
end process;
 
1178,37 → 1179,90
valid_lo := left(3 downto 0) <= 9;
valid_hi := left(7 downto 4) <= 9;
 
--
-- CBIT HBIT VHI VLO DAA
-- 0 0 0 0 66 (!VHI : hi_nybble>8)
-- 0 0 0 1 60
-- 0 0 1 1 00
-- 0 0 1 0 06 ( VHI : hi_nybble<=8)
--
-- 0 1 1 0 06
-- 0 1 1 1 06
-- 0 1 0 1 66
-- 0 1 0 0 66
--
-- 1 1 0 0 66
-- 1 1 0 1 66
-- 1 1 1 1 66
-- 1 1 1 0 66
--
-- 1 0 1 0 66
-- 1 0 1 1 60
-- 1 0 0 1 60
-- 1 0 0 0 66
--
-- 66 = (!VHI & !VLO) + (CBIT & HBIT) + (HBIT & !VHI) + (CBIT & !VLO)
-- = (CBIT & (HBIT + !VLO)) + (!VHI & (HBIT + !VLO))
-- = (!VLO & (CBIT + !VHI)) + (HBIT & (CBIT + !VHI))
-- 60 = (CBIT & !HBIT & VLO) + (!HBIT & !VHI & VLO)
-- = (!HBIT & VLO & (CBIT + !VHI))
-- 06 = (!CBIT & VHI & (!VLO + VHI)
-- 00 = (!CBIT & !HBIT & VHI & VLO)
--
if (cc(CBIT) = '0') then
if( cc(HBIT) = '1' ) then
if valid_hi then
daa_reg := "00000110";
else
daa_reg := "01100110";
end if;
else
-- CBIT=0
if( cc(HBIT) = '0' ) then
-- HBIT=0
if valid_lo then
-- lo <= 9 (no overflow in low nybble)
if valid_hi then
-- hi <= 9 (no overflow in either low or high nybble)
daa_reg := "00000000";
else
-- hi > 9 (overflow in high nybble only)
daa_reg := "01100000";
end if;
else
-- lo > 9 (overflow in low nybble)
--
-- since there is already an overflow in the low nybble
-- you need to make room in the high nybble for the low nybble carry
-- so compare the high nybble with 8 rather than 9
-- if the high nybble is 9 there will be an overflow on the high nybble
-- after the decimal adjust which means it will roll over to an invalid BCD digit
--
if( left(7 downto 4) <= 8 ) then
-- hi <= 8 (overflow in low nybble only)
daa_reg := "00000110";
else
-- hi > 8 (overflow in low and high nybble)
daa_reg := "01100110";
end if;
end if;
else
-- HBIT=1 (overflow in low nybble)
if valid_hi then
-- hi <= 9 (overflow in low nybble only)
daa_reg := "00000110";
else
-- hi > 9 (overflow in low and high nybble)
daa_reg := "01100110";
end if;
end if;
else
if ( cc(HBIT) = '1' )then
daa_reg := "01100110";
else
-- CBIT=1 (carry => overflow in high nybble)
if ( cc(HBIT) = '0' )then
-- HBIT=0 (half carry clear => may or may not be an overflow in the low nybble)
if valid_lo then
-- lo <=9 (overflow in high nybble only)
daa_reg := "01100000";
else
-- lo >9 (overflow in low and high nybble)
daa_reg := "01100110";
end if;
else
-- HBIT=1 (overflow in low and high nybble)
daa_reg := "01100110";
end if;
end if;
 
1484,1188 → 1538,986
------------------------------------
process( state, saved_state,
op_code, pre_code,
cc, ea, md, iv,
irq, firq, nmi_req, nmi_ack, halt )
cc, ea, md, iv, fic, halt,
nmi_req, firq, irq, lic )
variable cond_true : boolean; -- variable used to evaluate coditional branches
begin
ba <= '0';
bs <= '0';
lic <= '0';
-- Registers preserved
cond_true := (1=1);
ba <= '0';
bs <= '0';
lic <= '0';
opfetch <= '0';
iv_ctrl <= latch_iv;
-- Registers preserved
cc_ctrl <= latch_cc;
acca_ctrl <= latch_acca;
accb_ctrl <= latch_accb;
dp_ctrl <= latch_dp;
ix_ctrl <= latch_ix;
iy_ctrl <= latch_iy;
up_ctrl <= latch_up;
sp_ctrl <= latch_sp;
pc_ctrl <= latch_pc;
md_ctrl <= latch_md;
ea_ctrl <= latch_ea;
op_ctrl <= latch_op;
pre_ctrl <= latch_pre;
-- ALU Idle
left_ctrl <= pc_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
-- Bus idle
addr_ctrl <= idle_ad;
dout_ctrl <= cc_dout;
-- Next State Fetch
st_ctrl <= idle_st;
return_state <= fetch_state;
next_state <= fetch_state;
 
case state is
when reset_state => -- released from reset
-- reset the registers
iv_ctrl <= reset_iv;
op_ctrl <= reset_op;
pre_ctrl <= reset_pre;
cc_ctrl <= reset_cc;
acca_ctrl <= reset_acca;
accb_ctrl <= reset_accb;
dp_ctrl <= reset_dp;
ix_ctrl <= reset_ix;
iy_ctrl <= reset_iy;
up_ctrl <= reset_up;
sp_ctrl <= reset_sp;
pc_ctrl <= reset_pc;
ea_ctrl <= reset_ea;
md_ctrl <= reset_md;
st_ctrl <= reset_st;
next_state <= vect_hi_state;
 
--
-- Jump via interrupt vector
-- iv holds interrupt type
-- fetch PC hi from vector location
--
when vect_hi_state =>
-- fetch pc low interrupt vector
pc_ctrl <= pull_hi_pc;
addr_ctrl <= int_hi_ad;
bs <= '1';
next_state <= vect_lo_state;
 
--
-- jump via interrupt vector
-- iv holds vector type
-- fetch PC lo from vector location
--
when vect_lo_state =>
-- fetch the vector low byte
pc_ctrl <= pull_lo_pc;
addr_ctrl <= int_lo_ad;
bs <= '1';
next_state <= fetch_state;
 
when vect_idle_state =>
--
-- Last Instruction Cycle for SWI, SWI2 & SWI3
--
if op_code = "00111111" then
lic <= '1';
end if;
next_state <= fetch_state;
 
--
-- Here to fetch an instruction
-- PC points to opcode
--
when fetch_state =>
-- fetch the op code
opfetch <= '1';
op_ctrl <= fetch_op;
pre_ctrl <= fetch_pre;
ea_ctrl <= reset_ea;
-- Fetch op code
addr_ctrl <= fetch_ad;
-- Advance the PC to fetch next instruction byte
pc_ctrl <= incr_pc;
next_state <= decode1_state;
 
--
-- Here to decode instruction
-- and fetch next byte of intruction
-- whether it be necessary or not
--
when decode1_state =>
-- fetch first byte of address or immediate data
ea_ctrl <= fetch_first_ea;
md_ctrl <= fetch_first_md;
addr_ctrl <= fetch_ad;
case op_code(7 downto 4) is
--
-- direct single op (2 bytes)
-- 6809 => 6 cycles
-- cpu09 => 5 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 ea_hi=dp / ea_lo=(pc) / pc=pc+1
-- 3 md_lo=(ea) / pc=pc
-- 4 alu_left=md / md=alu_out / pc=pc
-- 5 (ea)=md_lo / pc=pc
--
-- Exception is JMP
-- 6809 => 3 cycles
-- cpu09 => 3 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 ea_hi=dp / ea_lo=(pc) / pc=pc+1
-- 3 pc=ea
--
when "0000" =>
-- advance the PC
pc_ctrl <= incr_pc;
 
case op_code(3 downto 0) is
when "1110" => -- jmp
next_state <= jmp_state;
 
when "1111" => -- clr
next_state <= single_op_exec_state;
 
when others =>
next_state <= single_op_read_state;
end case;
 
-- acca / accb inherent instructions
when "0001" =>
case op_code(3 downto 0) is
--
-- Page2 pre byte
-- pre=(pc) / pc=pc+1
-- op=(pc) / pc=pc+1
--
when "0000" => -- page2
opfetch <= '1';
op_ctrl <= fetch_op;
-- advance pc
pc_ctrl <= incr_pc;
next_state <= decode2_state;
 
--
-- Page3 pre byte
-- pre=(pc) / pc=pc+1
-- op=(pc) / pc=pc+1
--
when "0001" => -- page3
opfetch <= '1';
op_ctrl <= fetch_op;
-- advance pc
pc_ctrl <= incr_pc;
next_state <= decode3_state;
 
--
-- nop - No operation ( 1 byte )
-- 6809 => 2 cycles
-- cpu09 => 2 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 decode
--
when "0010" => -- nop
lic <= '1';
next_state <= fetch_state;
 
--
-- sync - halt execution until an interrupt is received
-- interrupt may be NMI, IRQ or FIRQ
-- program execution continues if the
-- interrupt is asserted for 3 clock cycles
-- note that registers are not pushed onto the stack
-- CPU09 => Interrupts need only be asserted for one clock cycle
--
when "0011" => -- sync
next_state <= sync_state;
 
--
-- lbra -- long branch (3 bytes)
-- 6809 => 5 cycles
-- cpu09 => 4 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1
-- 3 md_hi=md_lo / md_lo=(pc) / pc=pc+1
-- 4 pc=pc+md
--
when "0110" =>
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= lbranch_state;
 
--
-- lbsr - long branch to subroutine (3 bytes)
-- 6809 => 9 cycles
-- cpu09 => 6 cycles
-- 1 op=(pc) /pc=pc+1
-- 2 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1 / sp=sp-1
-- 3 md_hi=md_lo / md_lo=(pc) / pc=pc+1
-- 4 (sp)= pc_lo / sp=sp-1 / pc=pc
-- 5 (sp)=pc_hi / pc=pc
-- 6 pc=pc+md
--
when "0111" =>
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= lbranch_state;
 
--
-- Decimal Adjust Accumulator
--
when "1001" => -- daa
left_ctrl <= acca_left;
right_ctrl <= accb_right;
alu_ctrl <= alu_daa;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
lic <= '1';
next_state <= fetch_state;
 
--
-- OR Condition Codes
--
when "1010" => -- orcc
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= orcc_state;
 
--
-- AND Condition Codes
--
when "1100" => -- andcc
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= andcc_state;
 
--
-- Sign Extend
--
when "1101" => -- sex
left_ctrl <= accb_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_sex;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
lic <= '1';
next_state <= fetch_state;
 
--
-- Exchange Registers
--
when "1110" => -- exg
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= exg_state;
 
--
-- Transfer Registers
--
when "1111" => -- tfr
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= tfr_state;
 
when others =>
-- increment the pc
pc_ctrl <= incr_pc;
lic <= '1';
next_state <= fetch_state;
end case;
 
--
-- Short branch conditional
-- 6809 => always 3 cycles
-- cpu09 => always = 3 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1 / test cc
-- 3 if cc tru pc=pc+md else pc=pc
--
when "0010" => -- branch conditional
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= sbranch_state;
 
--
-- Single byte stack operators
-- Do not advance PC
--
when "0011" =>
--
-- lea - load effective address (2+ bytes)
-- 6809 => 4 cycles + addressing mode
-- cpu09 => 4 cycles + addressing mode
-- 1 op=(pc) / pc=pc+1
-- 2 md_lo=(pc) / pc=pc+1
-- 3 calculate ea
-- 4 ix/iy/sp/up = ea
--
case op_code(3 downto 0) is
when "0000" | -- leax
"0001" | -- leay
"0010" | -- leas
"0011" => -- leau
-- advance PC
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
return_state <= lea_state;
next_state <= indexed_state;
 
--
-- pshs - push registers onto sp stack
-- 6809 => 5 cycles + registers
-- cpu09 => 3 cycles + registers
-- 1 op=(pc) / pc=pc+1
-- 2 ea_lo=(pc) / pc=pc+1
-- 3 if ea(7 downto 0) != "00000000" then sp=sp-1
-- 4 if ea(7) = 1 (sp)=pcl, sp=sp-1
-- 5 if ea(7) = 1 (sp)=pch
-- if ea(6 downto 0) != "0000000" then sp=sp-1
-- 6 if ea(6) = 1 (sp)=upl, sp=sp-1
-- 7 if ea(6) = 1 (sp)=uph
-- if ea(5 downto 0) != "000000" then sp=sp-1
-- 8 if ea(5) = 1 (sp)=iyl, sp=sp-1
-- 9 if ea(5) = 1 (sp)=iyh
-- if ea(4 downto 0) != "00000" then sp=sp-1
-- 10 if ea(4) = 1 (sp)=ixl, sp=sp-1
-- 11 if ea(4) = 1 (sp)=ixh
-- if ea(3 downto 0) != "0000" then sp=sp-1
-- 12 if ea(3) = 1 (sp)=dp
-- if ea(2 downto 0) != "000" then sp=sp-1
-- 13 if ea(2) = 1 (sp)=accb
-- if ea(1 downto 0) != "00" then sp=sp-1
-- 14 if ea(1) = 1 (sp)=acca
-- if ea(0 downto 0) != "0" then sp=sp-1
-- 15 if ea(0) = 1 (sp)=cc
--
when "0100" => -- pshs
-- advance PC
pc_ctrl <= incr_pc;
next_state <= pshs_state;
 
--
-- puls - pull registers of sp stack
-- 6809 => 5 cycles + registers
-- cpu09 => 3 cycles + registers
--
when "0101" => -- puls
-- advance PC
pc_ctrl <= incr_pc;
next_state <= puls_state;
 
--
-- pshu - push registers onto up stack
-- 6809 => 5 cycles + registers
-- cpu09 => 3 cycles + registers
--
when "0110" => -- pshu
-- advance PC
pc_ctrl <= incr_pc;
next_state <= pshu_state;
--
-- pulu - pull registers of up stack
-- 6809 => 5 cycles + registers
-- cpu09 => 3 cycles + registers
--
when "0111" => -- pulu
-- advance PC
pc_ctrl <= incr_pc;
next_state <= pulu_state;
 
--
-- rts - return from subroutine
-- 6809 => 5 cycles
-- cpu09 => 4 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 decode op
-- 3 pc_hi = (sp) / sp=sp+1
-- 4 pc_lo = (sp) / sp=sp+1
--
when "1001" =>
next_state <= pull_return_hi_state;
 
--
-- ADD accb to index register
-- *** Note: this is an unsigned addition.
-- does not affect any condition codes
-- 6809 => 3 cycles
-- cpu09 => 2 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 alu_left=ix / alu_right=accb / ix=alu_out / pc=pc
--
when "1010" => -- abx
lic <= '1';
left_ctrl <= ix_left;
right_ctrl <= accb_right;
alu_ctrl <= alu_abx;
ix_ctrl <= load_ix;
next_state <= fetch_state;
 
--
-- Return From Interrupt
--
when "1011" => -- rti
next_state <= rti_cc_state;
 
--
-- CWAI
--
when "1100" => -- cwai #$<cc_mask>
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- increment pc
pc_ctrl <= incr_pc;
next_state <= cwai_state;
 
--
-- MUL Multiply
--
when "1101" => -- mul
next_state <= mul_state;
 
--
-- SWI Software Interrupt
--
when "1111" => -- swi
-- predecrement SP
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= swi_iv;
st_ctrl <= push_st;
return_state <= int_swimask_state;
next_state <= int_entire_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
 
end case;
--
-- Accumulator A Single operand
-- source = acca, dest = acca
-- Do not advance PC
-- Typically 2 cycles 1 bytes
-- 1 opcode fetch
-- 2 post byte fetch / instruction decode
-- Note that there is no post byte
-- so do not advance PC in decode cycle
-- Re-run opcode fetch cycle after decode
--
when "0100" => -- acca single op
left_ctrl <= acca_left;
case op_code(3 downto 0) is
when "0000" => -- neg
right_ctrl <= zero_right;
alu_ctrl <= alu_neg;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
when "0011" => -- com
right_ctrl <= zero_right;
alu_ctrl <= alu_com;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "0100" => -- lsr
right_ctrl <= zero_right;
alu_ctrl <= alu_lsr8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "0110" => -- ror
right_ctrl <= zero_right;
alu_ctrl <= alu_ror8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "0111" => -- asr
right_ctrl <= zero_right;
alu_ctrl <= alu_asr8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "1000" => -- asl
right_ctrl <= zero_right;
alu_ctrl <= alu_asl8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "1001" => -- rol
right_ctrl <= zero_right;
alu_ctrl <= alu_rol8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "1010" => -- dec
right_ctrl <= one_right;
alu_ctrl <= alu_dec;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "1011" => -- undefined
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
acca_ctrl <= latch_acca;
cc_ctrl <= latch_cc;
 
when "1100" => -- inc
right_ctrl <= one_right;
alu_ctrl <= alu_inc;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "1101" => -- tst
right_ctrl <= zero_right;
alu_ctrl <= alu_st8;
acca_ctrl <= latch_acca;
accb_ctrl <= latch_accb;
dp_ctrl <= latch_dp;
ix_ctrl <= latch_ix;
iy_ctrl <= latch_iy;
up_ctrl <= latch_up;
sp_ctrl <= latch_sp;
pc_ctrl <= latch_pc;
md_ctrl <= latch_md;
ea_ctrl <= latch_ea;
iv_ctrl <= latch_iv;
op_ctrl <= latch_op;
pre_ctrl <= latch_pre;
nmi_ctrl <= latch_nmi;
-- ALU Idle
left_ctrl <= pc_left;
cc_ctrl <= load_cc;
 
when "1110" => -- jmp (not defined)
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
-- Bus idle
addr_ctrl <= idle_ad;
dout_ctrl <= cc_dout;
-- Next State Fetch
st_ctrl <= idle_st;
return_state <= fetch_state;
next_state <= fetch_state;
acca_ctrl <= latch_acca;
cc_ctrl <= latch_cc;
 
case state is
when reset_state => -- released from reset
-- reset the registers
op_ctrl <= reset_op;
pre_ctrl <= reset_pre;
cc_ctrl <= reset_cc;
acca_ctrl <= reset_acca;
accb_ctrl <= reset_accb;
dp_ctrl <= reset_dp;
ix_ctrl <= reset_ix;
iy_ctrl <= reset_iy;
up_ctrl <= reset_up;
sp_ctrl <= reset_sp;
pc_ctrl <= reset_pc;
ea_ctrl <= reset_ea;
md_ctrl <= reset_md;
iv_ctrl <= reset_iv;
nmi_ctrl <= reset_nmi;
next_state <= vect_hi_state;
when "1111" => -- clr
right_ctrl <= zero_right;
alu_ctrl <= alu_clr;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
--
-- Jump via interrupt vector
-- iv holds interrupt type
-- fetch PC hi from vector location
--
when vect_hi_state =>
-- fetch pc low interrupt vector
pc_ctrl <= pull_hi_pc;
addr_ctrl <= int_hi_ad;
bs <= '1';
next_state <= vect_lo_state;
--
-- jump via interrupt vector
-- iv holds vector type
-- fetch PC lo from vector location
--
when vect_lo_state =>
-- fetch the vector low byte
pc_ctrl <= pull_lo_pc;
addr_ctrl <= int_lo_ad;
bs <= '1';
next_state <= fetch_state;
--
-- Here to fetch an instruction
-- PC points to opcode
-- Should service interrupt requests at this point
-- either from the timer
-- or from the external input.
--
when fetch_state =>
-- fetch the op code
op_ctrl <= fetch_op;
pre_ctrl <= fetch_pre;
ea_ctrl <= reset_ea;
-- Fetch op code
addr_ctrl <= fetch_ad;
--
case op_code(7 downto 6) is
when "10" => -- acca
case op_code(3 downto 0) is
when "0000" => -- suba
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub8;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "0001" => -- cmpa
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub8;
cc_ctrl <= load_cc;
when "0010" => -- sbca
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sbc;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "0011" =>
case pre_code is
when "00010000" => -- page 2 -- cmpd
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
when "00010001" => -- page 3 -- cmpu
left_ctrl <= up_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
when others => -- page 1 -- subd
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
end case;
when "0100" => -- anda
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_and;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "0101" => -- bita
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_and;
cc_ctrl <= load_cc;
when "0110" => -- ldaa
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld8;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "0111" => -- staa
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st8;
cc_ctrl <= load_cc;
when "1000" => -- eora
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_eor;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "1001" => -- adca
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_adc;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "1010" => -- oraa
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ora;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "1011" => -- adda
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_add8;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "1100" =>
case pre_code is
when "00010000" => -- page 2 -- cmpy
left_ctrl <= iy_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
when "00010001" => -- page 3 -- cmps
left_ctrl <= sp_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
when others => -- page 1 -- cmpx
left_ctrl <= ix_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
end case;
when "1101" => -- bsr / jsr
null;
when "1110" => -- ldx
case pre_code is
when "00010000" => -- page 2 -- ldy
left_ctrl <= iy_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
iy_ctrl <= load_iy;
when others => -- page 1 -- ldx
left_ctrl <= ix_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
ix_ctrl <= load_ix;
end case;
when "1111" => -- stx
case pre_code is
when "00010000" => -- page 2 -- sty
left_ctrl <= iy_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
when others => -- page 1 -- stx
left_ctrl <= ix_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
end case;
when others =>
null;
end case;
when "11" => -- accb dual op
case op_code(3 downto 0) is
when "0000" => -- subb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub8;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "0001" => -- cmpb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub8;
cc_ctrl <= load_cc;
when "0010" => -- sbcb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sbc;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "0011" => -- addd
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_add16;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
when "0100" => -- andb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_and;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "0101" => -- bitb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_and;
cc_ctrl <= load_cc;
when "0110" => -- ldab
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld8;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "0111" => -- stab
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st8;
cc_ctrl <= load_cc;
when "1000" => -- eorb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_eor;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "1001" => -- adcb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_adc;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "1010" => -- orab
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ora;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "1011" => -- addb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_add8;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "1100" => -- ldd
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
when "1101" => -- std
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
when "1110" => -- ldu
case pre_code is
when "00010000" => -- page 2 -- lds
left_ctrl <= sp_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
sp_ctrl <= load_sp;
when others => -- page 1 -- ldu
left_ctrl <= up_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
up_ctrl <= load_up;
end case;
when "1111" =>
case pre_code is
when "00010000" => -- page 2 -- sts
left_ctrl <= sp_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
when others => -- page 1 -- stu
left_ctrl <= up_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
end case;
when others =>
null;
end case;
when others =>
null;
end case;
if halt = '1' then
iv_ctrl <= reset_iv;
next_state <= halt_state;
-- service non maskable interrupts
elsif (nmi_req = '1') and (nmi_ack = '0') then
iv_ctrl <= nmi_iv;
nmi_ctrl <= set_nmi;
next_state <= int_nmiirq_state;
-- service maskable interrupts
else
--
-- nmi request is not cleared until nmi input goes low
--
if(nmi_req = '0') and (nmi_ack='1') then
nmi_ctrl <= reset_nmi;
end if;
--
-- FIRQ & IRQ are level sensitive
--
if (firq = '1') and (cc(FBIT) = '0') then
iv_ctrl <= firq_iv;
next_state <= int_firq_state;
elsif (irq = '1') and (cc(IBIT) = '0') then
iv_ctrl <= irq_iv;
next_state <= int_nmiirq_state;
else
-- Advance the PC to fetch next instruction byte
iv_ctrl <= reset_iv; -- default to reset
pc_ctrl <= incr_pc;
next_state <= decode1_state;
end if;
end if;
--
-- Here to decode instruction
-- and fetch next byte of intruction
-- whether it be necessary or not
--
when decode1_state =>
-- fetch first byte of address or immediate data
ea_ctrl <= fetch_first_ea;
md_ctrl <= fetch_first_md;
addr_ctrl <= fetch_ad;
case op_code(7 downto 4) is
--
-- direct single op (2 bytes)
-- 6809 => 6 cycles
-- cpu09 => 5 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 ea_hi=dp / ea_lo=(pc) / pc=pc+1
-- 3 md_lo=(ea) / pc=pc
-- 4 alu_left=md / md=alu_out / pc=pc
-- 5 (ea)=md_lo / pc=pc
--
-- Exception is JMP
-- 6809 => 3 cycles
-- cpu09 => 3 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 ea_hi=dp / ea_lo=(pc) / pc=pc+1
-- 3 pc=ea
--
when "0000" =>
-- advance the PC
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "1110" => -- jmp
next_state <= jmp_state;
when "1111" => -- clr
next_state <= single_op_exec_state;
when others =>
next_state <= single_op_read_state;
end case;
when others =>
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
acca_ctrl <= latch_acca;
cc_ctrl <= latch_cc;
 
-- acca / accb inherent instructions
when "0001" =>
case op_code(3 downto 0) is
--
-- Page2 pre byte
-- pre=(pc) / pc=pc+1
-- op=(pc) / pc=pc+1
--
when "0000" => -- page2
op_ctrl <= fetch_op;
-- advance pc
pc_ctrl <= incr_pc;
next_state <= decode2_state;
end case;
lic <= '1';
next_state <= fetch_state;
 
--
-- Page3 pre byte
-- pre=(pc) / pc=pc+1
-- op=(pc) / pc=pc+1
--
when "0001" => -- page3
op_ctrl <= fetch_op;
-- advance pc
pc_ctrl <= incr_pc;
next_state <= decode3_state;
--
-- Single Operand accb
-- source = accb, dest = accb
-- Typically 2 cycles 1 bytes
-- 1 opcode fetch
-- 2 post byte fetch / instruction decode
-- Note that there is no post byte
-- so do not advance PC in decode cycle
-- Re-run opcode fetch cycle after decode
--
when "0101" =>
left_ctrl <= accb_left;
case op_code(3 downto 0) is
when "0000" => -- neg
right_ctrl <= zero_right;
alu_ctrl <= alu_neg;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
--
-- nop - No operation ( 1 byte )
-- 6809 => 2 cycles
-- cpu09 => 2 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 decode
--
when "0010" => -- nop
lic <= '1';
next_state <= fetch_state;
when "0011" => -- com
right_ctrl <= zero_right;
alu_ctrl <= alu_com;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
--
-- sync - halt execution until an interrupt is received
-- interrupt may be NMI, IRQ or FIRQ
-- program execution continues if the
-- interrupt is asserted for 3 clock cycles
-- note that registers are not pushed onto the stack
-- CPU09 => Interrupts need only be asserted for one clock cycle
--
when "0011" => -- sync
next_state <= sync_state;
when "0100" => -- lsr
right_ctrl <= zero_right;
alu_ctrl <= alu_lsr8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
--
-- lbra -- long branch (3 bytes)
-- 6809 => 5 cycles
-- cpu09 => 4 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1
-- 3 md_hi=md_lo / md_lo=(pc) / pc=pc+1
-- 4 pc=pc+md
--
when "0110" =>
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= lbranch_state;
when "0110" => -- ror
right_ctrl <= zero_right;
alu_ctrl <= alu_ror8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
--
-- lbsr - long branch to subroutine (3 bytes)
-- 6809 => 9 cycles
-- cpu09 => 6 cycles
-- 1 op=(pc) /pc=pc+1
-- 2 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1 / sp=sp-1
-- 3 md_hi=md_lo / md_lo=(pc) / pc=pc+1
-- 4 (sp)= pc_lo / sp=sp-1 / pc=pc
-- 5 (sp)=pc_hi / pc=pc
-- 6 pc=pc+md
--
when "0111" =>
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= lbranch_state;
when "0111" => -- asr
right_ctrl <= zero_right;
alu_ctrl <= alu_asr8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "1001" => -- daa
left_ctrl <= acca_left;
right_ctrl <= accb_right;
alu_ctrl <= alu_daa;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
lic <= '1';
next_state <= fetch_state;
when "1000" => -- asl
right_ctrl <= zero_right;
alu_ctrl <= alu_asl8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "1010" => -- orcc
-- increment the pc
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= orcc_state;
when "1001" => -- rol
right_ctrl <= zero_right;
alu_ctrl <= alu_rol8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "1100" => -- andcc
-- increment the pc
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= andcc_state;
when "1010" => -- dec
right_ctrl <= one_right;
alu_ctrl <= alu_dec;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "1101" => -- sex
-- have sex
left_ctrl <= accb_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_sex;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
lic <= '1';
next_state <= fetch_state;
when "1011" => -- undefined
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
accb_ctrl <= latch_accb;
cc_ctrl <= latch_cc;
 
when "1110" => -- exg
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= exg_state;
when "1100" => -- inc
right_ctrl <= one_right;
alu_ctrl <= alu_inc;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "1111" => -- tfr
-- increment the pc
pc_ctrl <= incr_pc;
-- call transfer as a subroutine
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= tfr_state;
when "1101" => -- tst
right_ctrl <= zero_right;
alu_ctrl <= alu_st8;
accb_ctrl <= latch_accb;
cc_ctrl <= load_cc;
 
when others =>
-- increment the pc
pc_ctrl <= incr_pc;
lic <= '1';
next_state <= fetch_state;
end case;
--
-- Short branch conditional
-- 6809 => always 3 cycles
-- cpu09 => always = 3 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1 / test cc
-- 3 if cc tru pc=pc+md else pc=pc
--
when "0010" => -- branch conditional
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= sbranch_state;
--
-- Single byte stack operators
-- Do not advance PC
--
when "0011" =>
--
-- lea - load effective address (2+ bytes)
-- 6809 => 4 cycles + addressing mode
-- cpu09 => 4 cycles + addressing mode
-- 1 op=(pc) / pc=pc+1
-- 2 md_lo=(pc) / pc=pc+1
-- 3 calculate ea
-- 4 ix/iy/sp/up = ea
--
case op_code(3 downto 0) is
when "0000" | -- leax
"0001" | -- leay
"0010" | -- leas
"0011" => -- leau
-- advance PC
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
return_state <= lea_state;
next_state <= indexed_state;
when "1110" => -- jmp (undefined)
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
accb_ctrl <= latch_accb;
cc_ctrl <= latch_cc;
 
--
-- pshs - push registers onto sp stack
-- 6809 => 5 cycles + registers
-- cpu09 => 3 cycles + registers
-- 1 op=(pc) / pc=pc+1
-- 2 ea_lo=(pc) / pc=pc+1
-- 3 if ea(7 downto 0) != "00000000" then sp=sp-1
-- 4 if ea(7) = 1 (sp)=pcl, sp=sp-1
-- 5 if ea(7) = 1 (sp)=pch
-- if ea(6 downto 0) != "0000000" then sp=sp-1
-- 6 if ea(6) = 1 (sp)=upl, sp=sp-1
-- 7 if ea(6) = 1 (sp)=uph
-- if ea(5 downto 0) != "000000" then sp=sp-1
-- 8 if ea(5) = 1 (sp)=iyl, sp=sp-1
-- 9 if ea(5) = 1 (sp)=iyh
-- if ea(4 downto 0) != "00000" then sp=sp-1
-- 10 if ea(4) = 1 (sp)=ixl, sp=sp-1
-- 11 if ea(4) = 1 (sp)=ixh
-- if ea(3 downto 0) != "0000" then sp=sp-1
-- 12 if ea(3) = 1 (sp)=dp
-- if ea(2 downto 0) != "000" then sp=sp-1
-- 13 if ea(2) = 1 (sp)=accb
-- if ea(1 downto 0) != "00" then sp=sp-1
-- 14 if ea(1) = 1 (sp)=acca
-- if ea(0 downto 0) != "0" then sp=sp-1
-- 15 if ea(0) = 1 (sp)=cc
--
when "0100" => -- pshs
-- advance PC
pc_ctrl <= incr_pc;
next_state <= pshs_state;
when "1111" => -- clr
right_ctrl <= zero_right;
alu_ctrl <= alu_clr;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
--
-- puls - pull registers of sp stack
-- 6809 => 5 cycles + registers
-- cpu09 => 3 cycles + registers
--
when "0101" => -- puls
-- advance PC
pc_ctrl <= incr_pc;
next_state <= puls_state;
when others =>
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
accb_ctrl <= latch_accb;
cc_ctrl <= latch_cc;
end case;
lic <= '1';
next_state <= fetch_state;
 
--
-- pshu - push registers onto up stack
-- 6809 => 5 cycles + registers
-- cpu09 => 3 cycles + registers
--
when "0110" => -- pshu
-- advance PC
pc_ctrl <= incr_pc;
next_state <= pshu_state;
--
-- Single operand indexed
-- Two byte instruction so advance PC
-- EA should hold index offset
--
when "0110" => -- indexed single op
-- increment the pc
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
case op_code(3 downto 0) is
when "1110" => -- jmp
return_state <= jmp_state;
 
--
-- pulu - pull registers of up stack
-- 6809 => 5 cycles + registers
-- cpu09 => 3 cycles + registers
--
when "0111" => -- pulu
-- advance PC
pc_ctrl <= incr_pc;
next_state <= pulu_state;
when "1111" => -- clr
return_state <= single_op_exec_state;
 
--
-- rts - return from subroutine
-- 6809 => 5 cycles
-- cpu09 => 4 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 decode op
-- 3 pc_hi = (sp) / sp=sp+1
-- 4 pc_lo = (sp) / sp=sp+1
--
when "1001" =>
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= pull_return_hi_state;
when others =>
return_state <= single_op_read_state;
 
--
-- add accb to index register
-- *** Note: this is an unsigned addition.
-- does not affect any condition codes
-- 6809 => 3 cycles
-- cpu09 => 2 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 alu_left=ix / alu_right=accb / ix=alu_out / pc=pc
--
when "1010" => -- abx
left_ctrl <= ix_left;
right_ctrl <= accb_right;
alu_ctrl <= alu_abx;
ix_ctrl <= load_ix;
lic <= '1';
next_state <= fetch_state;
end case;
next_state <= indexed_state;
 
when "1011" => -- rti
next_state <= rti_cc_state;
--
-- Single operand extended addressing
-- three byte instruction so advance the PC
-- Low order EA holds high order address
--
when "0111" => -- extended single op
-- increment PC
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
 
when "1100" => -- cwai #$<cc_mask>
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= reset_iv;
-- increment pc
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
return_state <= int_entire_state; -- set entire flag
next_state <= andcc_state;
case op_code(3 downto 0) is
when "1110" => -- jmp
return_state <= jmp_state;
when "1111" => -- clr
return_state <= single_op_exec_state;
when others =>
return_state <= single_op_read_state;
end case;
next_state <= extended_state;
 
when "1101" => -- mul
next_state <= mul_state;
when "1000" => -- acca immediate
-- increment the pc
pc_ctrl <= incr_pc;
 
when "1111" => -- swi
-- predecrement SP
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= swi_iv;
next_state <= int_entire_state;
case op_code(3 downto 0) is
when "0011" | -- subd #
"1100" | -- cmpx #
"1110" => -- ldx #
next_state <= imm16_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
--
-- bsr offset - Branch to subroutine (2 bytes)
-- 6809 => 7 cycles
-- cpu09 => 5 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 md_hi=sign(pc) / md_lo=(pc) / sp=sp-1 / pc=pc+1
-- 3 (sp)=pc_lo / sp=sp-1
-- 4 (sp)=pc_hi
-- 5 pc=pc+md
--
when "1101" => -- bsr
-- pre decrement SP
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
--
st_ctrl <= push_st;
return_state <= sbranch_state;
next_state <= push_return_lo_state;
 
end case;
--
-- Accumulator A Single operand
-- source = acca, dest = acca
-- Do not advance PC
-- Typically 2 cycles 1 bytes
-- 1 opcode fetch
-- 2 post byte fetch / instruction decode
-- Note that there is no post byte
-- so do not advance PC in decode cycle
-- Re-run opcode fetch cycle after decode
--
when "0100" => -- acca single op
left_ctrl <= acca_left;
case op_code(3 downto 0) is
when "0000" => -- neg
right_ctrl <= zero_right;
alu_ctrl <= alu_neg;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
when "0011" => -- com
right_ctrl <= zero_right;
alu_ctrl <= alu_com;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
when "0100" => -- lsr
right_ctrl <= zero_right;
alu_ctrl <= alu_lsr8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
when "0110" => -- ror
right_ctrl <= zero_right;
alu_ctrl <= alu_ror8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
when "0111" => -- asr
right_ctrl <= zero_right;
alu_ctrl <= alu_asr8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
when "1000" => -- asl
right_ctrl <= zero_right;
alu_ctrl <= alu_asl8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
when "1001" => -- rol
right_ctrl <= zero_right;
alu_ctrl <= alu_rol8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
when "1010" => -- dec
right_ctrl <= one_right;
alu_ctrl <= alu_dec;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
when "1011" => -- undefined
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
acca_ctrl <= latch_acca;
cc_ctrl <= latch_cc;
when "1100" => -- inc
right_ctrl <= one_right;
alu_ctrl <= alu_inc;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
when "1101" => -- tst
right_ctrl <= zero_right;
alu_ctrl <= alu_st8;
acca_ctrl <= latch_acca;
cc_ctrl <= load_cc;
when "1110" => -- jmp (not defined)
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
acca_ctrl <= latch_acca;
cc_ctrl <= latch_cc;
when "1111" => -- clr
right_ctrl <= zero_right;
alu_ctrl <= alu_clr;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
when others =>
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
acca_ctrl <= latch_acca;
cc_ctrl <= latch_cc;
end case;
lic <= '1';
next_state <= fetch_state;
--
-- Single Operand accb
-- source = accb, dest = accb
-- Typically 2 cycles 1 bytes
-- 1 opcode fetch
-- 2 post byte fetch / instruction decode
-- Note that there is no post byte
-- so do not advance PC in decode cycle
-- Re-run opcode fetch cycle after decode
--
when "0101" =>
left_ctrl <= accb_left;
case op_code(3 downto 0) is
when "0000" => -- neg
right_ctrl <= zero_right;
alu_ctrl <= alu_neg;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
when "0011" => -- com
right_ctrl <= zero_right;
alu_ctrl <= alu_com;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
when "0100" => -- lsr
right_ctrl <= zero_right;
alu_ctrl <= alu_lsr8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
when "0110" => -- ror
right_ctrl <= zero_right;
alu_ctrl <= alu_ror8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
when "0111" => -- asr
right_ctrl <= zero_right;
alu_ctrl <= alu_asr8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
when "1000" => -- asl
right_ctrl <= zero_right;
alu_ctrl <= alu_asl8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
when "1001" => -- rol
right_ctrl <= zero_right;
alu_ctrl <= alu_rol8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
when "1010" => -- dec
right_ctrl <= one_right;
alu_ctrl <= alu_dec;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
when "1011" => -- undefined
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
accb_ctrl <= latch_accb;
cc_ctrl <= latch_cc;
when "1100" => -- inc
right_ctrl <= one_right;
alu_ctrl <= alu_inc;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
when "1101" => -- tst
right_ctrl <= zero_right;
alu_ctrl <= alu_st8;
accb_ctrl <= latch_accb;
cc_ctrl <= load_cc;
when "1110" => -- jmp (undefined)
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
accb_ctrl <= latch_accb;
cc_ctrl <= latch_cc;
when "1111" => -- clr
right_ctrl <= zero_right;
alu_ctrl <= alu_clr;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
when others =>
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
accb_ctrl <= latch_accb;
cc_ctrl <= latch_cc;
end case;
lic <= '1';
next_state <= fetch_state;
--
-- Single operand indexed
-- Two byte instruction so advance PC
-- EA should hold index offset
--
when "0110" => -- indexed single op
-- increment the pc
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
case op_code(3 downto 0) is
when "1110" => -- jmp
return_state <= jmp_state;
when "1111" => -- clr
return_state <= single_op_exec_state;
when others =>
return_state <= single_op_read_state;
end case;
next_state <= indexed_state;
--
-- Single operand extended addressing
-- three byte instruction so advance the PC
-- Low order EA holds high order address
--
when "0111" => -- extended single op
-- increment PC
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
case op_code(3 downto 0) is
when "1110" => -- jmp
return_state <= jmp_state;
when "1111" => -- clr
return_state <= single_op_exec_state;
when others =>
return_state <= single_op_read_state;
end case;
next_state <= extended_state;
when others =>
lic <= '1';
next_state <= fetch_state;
 
when "1000" => -- acca immediate
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- subd #
"1100" | -- cmpx #
"1110" => -- ldx #
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= imm16_state;
end case;
 
--
-- bsr offset - Branch to subroutine (2 bytes)
-- 6809 => 7 cycles
-- cpu09 => 5 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 md_hi=sign(pc) / md_lo=(pc) / sp=sp-1 / pc=pc+1
-- 3 (sp)=pc_lo / sp=sp-1
-- 4 (sp)=pc_hi
-- 5 pc=pc+md
--
when "1101" => -- bsr
-- pre decrement SP
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
--
st_ctrl <= push_st;
return_state <= sbranch_state;
next_state <= push_return_lo_state;
when "1001" => -- acca direct
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- subd
"1100" | -- cmpx
"1110" => -- ldx
next_state <= dual_op_read16_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
end case;
when "0111" => -- sta direct
next_state <= dual_op_write8_state;
 
when "1001" => -- acca direct
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- subd
"1100" | -- cmpx
"1110" => -- ldx
next_state <= dual_op_read16_state;
--
-- jsr direct - Jump to subroutine in direct page (2 bytes)
-- 6809 => 7 cycles
-- cpu09 => 5 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 ea_hi=0 / ea_lo=(pc) / sp=sp-1 / pc=pc+1
-- 3 (sp)=pc_lo / sp=sp-1
-- 4 (sp)=pc_hi
-- 5 pc=ea
--
when "1101" => -- jsr direct
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
--
st_ctrl <= push_st;
return_state <= jmp_state;
next_state <= push_return_lo_state;
 
when "0111" => -- sta direct
next_state <= dual_op_write8_state;
 
when "1111" => -- stx direct
-- idle ALU
left_ctrl <= ix_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
cc_ctrl <= latch_cc;
sp_ctrl <= latch_sp;
next_state <= dual_op_write16_state;
when "1111" => -- stx direct
-- idle ALU
left_ctrl <= ix_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
cc_ctrl <= latch_cc;
sp_ctrl <= latch_sp;
next_state <= dual_op_write16_state;
 
--
-- jsr direct - Jump to subroutine in direct page (2 bytes)
-- 6809 => 7 cycles
-- cpu09 => 5 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 ea_hi=0 / ea_lo=(pc) / sp=sp-1 / pc=pc+1
-- 3 (sp)=pc_lo / sp=sp-1
-- 4 (sp)=pc_hi
-- 5 pc=ea
--
when "1101" => -- jsr direct
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
--
st_ctrl <= push_st;
return_state <= jmp_state;
next_state <= push_return_lo_state;
when others =>
next_state <= dual_op_read8_state;
 
when others =>
next_state <= dual_op_read8_state;
end case;
end case;
 
when "1010" => -- acca indexed
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- subd
"1100" | -- cmpx
"1110" => -- ldx
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= indexed_state;
when "1010" => -- acca indexed
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- subd
"1100" | -- cmpx
"1110" => -- ldx
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= indexed_state;
 
when "0111" => -- staa ,x
st_ctrl <= push_st;
return_state <= dual_op_write8_state;
next_state <= indexed_state;
when "0111" => -- staa ,x
st_ctrl <= push_st;
return_state <= dual_op_write8_state;
next_state <= indexed_state;
 
when "1111" => -- stx ,x
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= indexed_state;
when "1101" => -- jsr ,x
-- DO NOT pre decrement SP
st_ctrl <= push_st;
return_state <= jsr_state;
next_state <= indexed_state;
 
when "1101" => -- jsr ,x
-- DO NOT pre decrement SP
st_ctrl <= push_st;
return_state <= jsr_state;
next_state <= indexed_state;
when "1111" => -- stx ,x
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= indexed_state;
 
when others =>
st_ctrl <= push_st;
return_state <= dual_op_read8_state;
next_state <= indexed_state;
end case;
when others =>
st_ctrl <= push_st;
return_state <= dual_op_read8_state;
next_state <= indexed_state;
end case;
 
when "1011" => -- acca extended
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- subd
"1100" | -- cmpx
"1110" => -- ldx
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= extended_state;
when "1011" => -- acca extended
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- subd
"1100" | -- cmpx
"1110" => -- ldx
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= extended_state;
 
when "0111" => -- staa >
st_ctrl <= push_st;
return_state <= dual_op_write8_state;
next_state <= extended_state;
when "0111" => -- staa >
st_ctrl <= push_st;
return_state <= dual_op_write8_state;
next_state <= extended_state;
 
when "1111" => -- stx >
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= extended_state;
when "1101" => -- jsr >extended
-- DO NOT pre decrement sp
st_ctrl <= push_st;
return_state <= jsr_state;
next_state <= extended_state;
 
when "1101" => -- jsr >extended
-- DO NOT pre decrement sp
st_ctrl <= push_st;
return_state <= jsr_state;
next_state <= extended_state;
when "1111" => -- stx >
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= extended_state;
 
when others =>
st_ctrl <= push_st;
return_state <= dual_op_read8_state;
next_state <= extended_state;
end case;
when others =>
st_ctrl <= push_st;
return_state <= dual_op_read8_state;
next_state <= extended_state;
 
when "1100" => -- accb immediate
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- addd #
"1100" | -- ldd #
"1110" => -- ldu #
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= imm16_state;
end case;
 
when others =>
lic <= '1';
next_state <= fetch_state;
when "1100" => -- accb immediate
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- addd #
"1100" | -- ldd #
"1110" => -- ldu #
next_state <= imm16_state;
 
end case;
when others =>
lic <= '1';
next_state <= fetch_state;
 
end case;
 
when "1101" => -- accb direct
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- addd
"1100" | -- ldd
"1110" => -- ldu
next_state <= dual_op_read16_state;
when "1101" => -- accb direct
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- addd
"1100" | -- ldd
"1110" => -- ldu
next_state <= dual_op_read16_state;
 
when "0111" => -- stab direct
next_state <= dual_op_write8_state;
when "0111" => -- stab direct
next_state <= dual_op_write8_state;
 
when "1101" => -- std direct
next_state <= dual_op_write16_state;
when "1101" => -- std direct
next_state <= dual_op_write16_state;
 
when "1111" => -- stu direct
next_state <= dual_op_write16_state;
when "1111" => -- stu direct
next_state <= dual_op_write16_state;
 
when others =>
next_state <= dual_op_read8_state;
end case;
when others =>
next_state <= dual_op_read8_state;
 
when "1110" => -- accb indexed
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- addd
"1100" | -- ldd
"1110" => -- ldu
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= indexed_state;
end case;
 
when "0111" => -- stab indexed
st_ctrl <= push_st;
return_state <= dual_op_write8_state;
next_state <= indexed_state;
when "1110" => -- accb indexed
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- addd
"1100" | -- ldd
"1110" => -- ldu
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= indexed_state;
 
when "1101" => -- std indexed
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= indexed_state;
when "0111" => -- stab indexed
st_ctrl <= push_st;
return_state <= dual_op_write8_state;
next_state <= indexed_state;
 
when "1111" => -- stu indexed
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= indexed_state;
when "1101" => -- std indexed
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= indexed_state;
 
when others =>
st_ctrl <= push_st;
return_state <= dual_op_read8_state;
next_state <= indexed_state;
end case;
when "1111" => -- stu indexed
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= indexed_state;
 
when "1111" => -- accb extended
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- addd
"1100" | -- ldd
"1110" => -- ldu
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= extended_state;
when others =>
st_ctrl <= push_st;
return_state <= dual_op_read8_state;
next_state <= indexed_state;
end case;
 
when "0111" => -- stab extended
st_ctrl <= push_st;
return_state <= dual_op_write8_state;
next_state <= extended_state;
when "1111" => -- accb extended
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- addd
"1100" | -- ldd
"1110" => -- ldu
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= extended_state;
 
when "1101" => -- std extended
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= extended_state;
when "0111" => -- stab extended
st_ctrl <= push_st;
return_state <= dual_op_write8_state;
next_state <= extended_state;
 
when "1111" => -- stu extended
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= extended_state;
when "1101" => -- std extended
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= extended_state;
 
when others =>
st_ctrl <= push_st;
return_state <= dual_op_read8_state;
next_state <= extended_state;
end case;
when "1111" => -- stu extended
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= extended_state;
 
when others =>
null;
end case;
when others =>
st_ctrl <= push_st;
return_state <= dual_op_read8_state;
next_state <= extended_state;
end case;
--
-- not sure why I need this
--
when others =>
lic <= '1';
next_state <= fetch_state;
end case;
 
--
-- Here to decode prefix 2 instruction
2701,12 → 2553,14
case op_code(3 downto 0) is
when "1111" => -- swi 2
-- predecrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= swi2_iv;
next_state <= int_entire_state;
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= swi2_iv;
st_ctrl <= push_st;
return_state <= vect_hi_state;
next_state <= int_entire_state;
 
when others =>
lic <= '1';
2720,8 → 2574,6
when "0011" | -- cmpd #
"1100" | -- cmpy #
"1110" => -- ldy #
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= imm16_state;
 
when others =>
2798,8 → 2650,6
when "0011" | -- undef #
"1100" | -- undef #
"1110" => -- lds #
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= imm16_state;
 
when others =>
2891,12 → 2741,14
case op_code(3 downto 0) is
when "1111" => -- swi3
-- predecrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= swi3_iv;
next_state <= int_entire_state;
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= swi3_iv;
st_ctrl <= push_st;
return_state <= vect_hi_state;
next_state <= int_entire_state;
when others =>
lic <= '1';
next_state <= fetch_state;
2909,8 → 2761,6
when "0011" | -- cmpu #
"1100" | -- cmps #
"1110" => -- undef #
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= imm16_state;
when others =>
lic <= '1';
2924,8 → 2774,6
when "0011" | -- cmpu <
"1100" | -- cmps <
"1110" => -- undef <
st_ctrl <= idle_st;
return_state <= fetch_state;
next_state <= dual_op_read16_state;
 
when others =>
3229,9 → 3077,8
-- fetch next immediate byte
md_ctrl <= fetch_next_md;
addr_ctrl <= fetch_ad;
st_ctrl <= pull_st;
lic <= '1';
next_state <= saved_state;
next_state <= fetch_state;
 
--
-- md & ea holds 8 bit index offset
3257,7 → 3104,6
right_ctrl <= md_sign5_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
st_ctrl <= pull_st;
next_state <= saved_state;
 
else
3315,7 → 3161,6
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
ea_ctrl <= load_ea;
st_ctrl <= pull_st;
next_state <= saved_state;
 
when "0011" => -- ,--R
3338,7 → 3183,6
alu_ctrl <= alu_sub16;
ea_ctrl <= load_ea;
if md(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3360,7 → 3204,6
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
if md(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3382,7 → 3225,6
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
if md(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3404,7 → 3246,6
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
if md(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3426,7 → 3267,6
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
if md(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3461,7 → 3301,6
ea_ctrl <= load_ea;
--
if md(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3483,7 → 3322,6
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
if md(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3519,7 → 3357,6
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
if md(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3553,7 → 3390,6
end case;
-- return to previous state
if md(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3578,7 → 3414,6
end case;
-- return to previous state
if md(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3605,7 → 3440,6
ea_ctrl <= load_ea;
-- return to previous state
if ea(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3640,7 → 3474,6
ea_ctrl <= load_ea;
-- return to previous state
if ea(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3657,7 → 3490,6
ea_ctrl <= load_ea;
-- return to previous state
if ea(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3684,7 → 3516,6
ea_ctrl <= load_ea;
-- return to previous state
if ea(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3712,7 → 3543,6
ea_ctrl <= load_ea;
-- return to previous state
if ea(4) = '0' then
st_ctrl <= pull_st;
next_state <= saved_state;
else
next_state <= indirect_state;
3755,7 → 3585,6
alu_ctrl <= alu_ld16;
ea_ctrl <= load_ea;
-- return to previous state
st_ctrl <= pull_st;
next_state <= saved_state;
 
--
3771,7 → 3600,6
ea_ctrl <= fetch_next_ea;
addr_ctrl <= fetch_ad;
-- return to previous state
st_ctrl <= pull_st;
next_state <= saved_state;
 
when lea_state => -- here on load effective address
3898,10 → 3726,8
when others =>
null;
end case;
else
cond_true := (1 = 1); -- lbra, lbsr, bsr
end if;
if cond_true then
if cond_true then
pc_ctrl <= load_pc;
end if;
lic <= '1';
3934,9 → 3760,11
-- write pc hi bytes
addr_ctrl <= pushs_ad;
dout_ctrl <= pc_hi_dout;
st_ctrl <= pull_st;
next_state <= saved_state;
 
--
-- RTS pull return address from stack
--
when pull_return_hi_state =>
-- increment the sp
left_ctrl <= sp_left;
3959,9 → 3787,8
addr_ctrl <= pulls_ad;
dout_ctrl <= pc_lo_dout;
--
st_ctrl <= pull_st;
lic <= '1';
next_state <= saved_state;
next_state <= fetch_state;
 
when andcc_state =>
-- AND CC with md
3970,9 → 3797,8
alu_ctrl <= alu_andcc;
cc_ctrl <= load_cc;
--
st_ctrl <= pull_st;
lic <= '1';
next_state <= saved_state;
next_state <= fetch_state;
 
when orcc_state =>
-- OR CC with md
3981,9 → 3807,8
alu_ctrl <= alu_orcc;
cc_ctrl <= load_cc;
--
st_ctrl <= pull_st;
lic <= '1';
next_state <= saved_state;
next_state <= fetch_state;
 
when tfr_state =>
-- select source register
4040,9 → 3865,8
null;
end case;
--
st_ctrl <= pull_st;
lic <= '1';
next_state <= saved_state;
next_state <= fetch_state;
 
when exg_state =>
-- save destination register
4074,11 → 3898,65
alu_ctrl <= alu_tfr;
ea_ctrl <= load_ea;
-- call tranfer microcode
st_ctrl <= push_st;
return_state <= exg1_state;
next_state <= tfr_state;
next_state <= exg1_state;
 
when exg1_state =>
-- select source register
case md(7 downto 4) is
when "0000" =>
left_ctrl <= accd_left;
when "0001" =>
left_ctrl <= ix_left;
when "0010" =>
left_ctrl <= iy_left;
when "0011" =>
left_ctrl <= up_left;
when "0100" =>
left_ctrl <= sp_left;
when "0101" =>
left_ctrl <= pc_left;
when "1000" =>
left_ctrl <= acca_left;
when "1001" =>
left_ctrl <= accb_left;
when "1010" =>
left_ctrl <= cc_left;
when "1011" =>
left_ctrl <= dp_left;
when others =>
left_ctrl <= md_left;
end case;
right_ctrl <= zero_right;
alu_ctrl <= alu_tfr;
-- select destination register
case md(3 downto 0) is
when "0000" => -- accd
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
when "0001" => -- ix
ix_ctrl <= load_ix;
when "0010" => -- iy
iy_ctrl <= load_iy;
when "0011" => -- up
up_ctrl <= load_up;
when "0100" => -- sp
sp_ctrl <= load_sp;
when "0101" => -- pc
pc_ctrl <= load_pc;
when "1000" => -- acca
acca_ctrl <= load_acca;
when "1001" => -- accb
accb_ctrl <= load_accb;
when "1010" => -- cc
cc_ctrl <= load_cc;
when "1011" => --dp
dp_ctrl <= load_dp;
when others =>
null;
end case;
next_state <= exg2_state;
 
when exg2_state =>
-- restore destination
left_ctrl <= ea_left;
right_ctrl <= zero_right;
5431,21 → 5309,137
next_state <= fetch_state;
 
--
-- here on IRQ or NMI interrupt
-- here on NMI interrupt
-- Complete execute cycle of the last instruction.
-- If it was a dual operand instruction
--
when int_nmi_state =>
next_state <= int_nmi1_state;
 
-- Idle bus cycle
when int_nmi1_state =>
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= nmi_iv;
st_ctrl <= push_st;
return_state <= int_nmimask_state;
next_state <= int_entire_state;
 
--
-- here on IRQ interrupt
-- Complete execute cycle of the last instruction.
-- If it was a dual operand instruction
--
when int_irq_state =>
next_state <= int_irq1_state;
 
-- pre decrement the sp
-- Idle bus cycle
when int_irq1_state =>
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= irq_iv;
st_ctrl <= push_st;
return_state <= int_irqmask_state;
next_state <= int_entire_state;
 
--
when int_nmiirq_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
next_state <= int_entire_state;
-- here on FIRQ interrupt
-- Complete execution cycle of the last instruction
-- if it was a dual operand instruction
--
when int_firq_state =>
next_state <= int_firq1_state;
 
-- Idle bus cycle
when int_firq1_state =>
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= firq_iv;
st_ctrl <= push_st;
return_state <= int_firqmask_state;
next_state <= int_fast_state;
 
--
-- CWAI entry point
-- stack pointer already pre-decremented
-- mask condition codes
--
when cwai_state =>
-- AND CC with md
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_andcc;
cc_ctrl <= load_cc;
st_ctrl <= push_st;
return_state <= int_cwai_state;
next_state <= int_entire_state;
 
--
-- wait here for an interrupt
--
when int_cwai_state =>
if (nmi_req = '1') then
iv_ctrl <= nmi_iv;
next_state <= int_nmimask_state;
--
-- FIRQ & IRQ are level sensitive
--
elsif (firq = '1') and (cc(FBIT) = '0') then
iv_ctrl <= firq_iv;
next_state <= int_firqmask_state;
 
elsif (irq = '1') and (cc(IBIT) = '0') then
iv_ctrl <= irq_iv;
next_state <= int_irqmask_state;
else
next_state <= int_cwai_state;
end if;
--
-- State to mask I Flag and F Flag (NMI)
--
when int_nmimask_state =>
alu_ctrl <= alu_seif;
cc_ctrl <= load_cc;
next_state <= vect_hi_state;
 
--
-- State to mask I Flag and F Flag (FIRQ)
--
when int_firqmask_state =>
alu_ctrl <= alu_seif;
cc_ctrl <= load_cc;
next_state <= vect_hi_state;
 
 
--
-- State to mask I Flag and F Flag (SWI)
--
when int_swimask_state =>
alu_ctrl <= alu_seif;
cc_ctrl <= load_cc;
next_state <= vect_hi_state;
 
--
-- State to mask I Flag only (IRQ)
--
when int_irqmask_state =>
alu_ctrl <= alu_sei;
cc_ctrl <= load_cc;
next_state <= vect_hi_state;
 
--
-- set Entire Flag on SWI, SWI2, SWI3 and CWAI, IRQ and NMI
-- clear Entire Flag on FIRQ
-- before stacking all registers
--
when int_entire_state =>
5453,20 → 5447,8
alu_ctrl <= alu_see;
cc_ctrl <= load_cc;
next_state <= int_pcl_state;
 
--
-- here on FIRQ interrupt
-- pre decrement the sp
-- Idle bus cycle
--
when int_firq_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
next_state <= int_fast_state;
--
-- clear Entire Flag on FIRQ
-- before stacking all registers
--
5605,71 → 5587,9
-- write cc
addr_ctrl <= pushs_ad;
dout_ctrl <= cc_dout;
case iv is
when NMI_VEC =>
next_state <= int_maskif_state;
when SWI_VEC =>
next_state <= int_maskif_state;
when FIRQ_VEC =>
next_state <= int_maskif_state;
when IRQ_VEC =>
next_state <= int_maski_state;
when SWI2_VEC =>
next_state <= vect_hi_state;
when SWI3_VEC =>
next_state <= vect_hi_state;
when others =>
if op_code = "00111100" then -- CWAI
next_state <= int_cwai_state;
else
next_state <= rti_cc_state; -- spurious interrupt, do a RTI
end if;
end case;
next_state <= saved_state;
 
--
-- wait here for an inteerupt
--
when int_cwai_state =>
if (nmi_req = '1') and (nmi_ack='0') then
iv_ctrl <= nmi_iv;
nmi_ctrl <= set_nmi;
next_state <= int_maskif_state;
else
--
-- nmi request is not cleared until nmi input goes low
--
if (nmi_req = '0') and (nmi_ack='1') then
nmi_ctrl <= reset_nmi;
end if;
--
-- FIRQ is level sensitive
--
if (firq = '1') and (cc(FBIT) = '0') then
iv_ctrl <= firq_iv;
next_state <= int_maskif_state;
--
-- IRQ is level sensitive
--
elsif (irq = '1') and (cc(IBIT) = '0') then
iv_ctrl <= irq_iv;
next_state <= int_maski_state;
else
iv_ctrl <= reset_iv;
next_state <= int_cwai_state;
end if;
end if;
 
when int_maski_state =>
alu_ctrl <= alu_sei;
cc_ctrl <= load_cc;
next_state <= vect_hi_state;
 
when int_maskif_state =>
alu_ctrl <= alu_seif;
cc_ctrl <= load_cc;
next_state <= vect_hi_state;
 
--
-- According to the 6809 programming manual:
-- If an interrupt is received and is masked
-- or lasts for less than three cycles, the PC
5681,63 → 5601,305
-- John Kent 11th July 2006
--
when sync_state =>
if (nmi_req = '1') and (nmi_ack='0') then
iv_ctrl <= nmi_iv;
nmi_ctrl <= set_nmi;
next_state <= int_nmiirq_state;
else
--
-- nmi request is not cleared until nmi input goes low
--
if (nmi_req = '0') and (nmi_ack='1') then
iv_ctrl <= reset_iv;
nmi_ctrl <= reset_nmi;
end if;
--
-- FIRQ is level sensitive
--
if (firq = '1') then
if (cc(FBIT) = '0') then
iv_ctrl <= firq_iv;
next_state <= int_firq_state;
else
iv_ctrl <= reset_iv;
lic <= '1';
next_state <= fetch_state;
end if;
--
-- IRQ is level sensitive
--
elsif (irq = '1') then
if (cc(IBIT) = '0') then
iv_ctrl <= irq_iv;
next_state <= int_nmiirq_state;
else
iv_ctrl <= reset_iv;
lic <= '1';
next_state <= fetch_state;
end if;
else
iv_ctrl <= reset_iv;
ba <= '1';
next_state <= sync_state;
end if;
end if;
 
 
lic <= '1';
ba <= '1';
--
-- Version 1.28 2015-05-30
-- Exit sync_state on interrupt.
-- If the interrupts are active
-- they will be caught in the state_machine process
-- and the interrupt service routine microcode will be executed.
-- Masked interrupts will exit the sync_state.
-- Moved from the state_machine process to the state_sequencer process
--
if (firq = '1') or (irq = '1') then
next_state <= fetch_state;
else
next_state <= sync_state;
end if;
when halt_state =>
--
-- 2011-10-30 John Kent
-- ba & bs should be high
ba <= '1';
bs <= '1';
if halt = '1' then
ba <= '1';
bs <= '1';
next_state <= halt_state;
else
lic <= '1';
next_state <= fetch_state;
next_state <= fetch_state;
end if;
 
when others => -- halt on undefine states
next_state <= error_state;
end case;
 
--
-- Ver 1.23 2011-10-30 John Kent
-- First instruction cycle might be
-- fetch_state
-- halt_state
-- int_nmirq_state
-- int_firq_state
--
if fic = '1' then
--
case op_code(7 downto 6) is
when "10" => -- acca
case op_code(3 downto 0) is
when "0000" => -- suba
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub8;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "0001" => -- cmpa
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub8;
cc_ctrl <= load_cc;
when "0010" => -- sbca
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sbc;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "0011" =>
case pre_code is
when "00010000" => -- page 2 -- cmpd
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
when "00010001" => -- page 3 -- cmpu
left_ctrl <= up_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
when others => -- page 1 -- subd
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
end case;
when "0100" => -- anda
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_and;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "0101" => -- bita
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_and;
cc_ctrl <= load_cc;
when "0110" => -- ldaa
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld8;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "0111" => -- staa
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st8;
cc_ctrl <= load_cc;
when "1000" => -- eora
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_eor;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "1001" => -- adca
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_adc;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "1010" => -- oraa
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ora;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "1011" => -- adda
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_add8;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "1100" =>
case pre_code is
when "00010000" => -- page 2 -- cmpy
left_ctrl <= iy_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
when "00010001" => -- page 3 -- cmps
left_ctrl <= sp_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
when others => -- page 1 -- cmpx
left_ctrl <= ix_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
end case;
when "1101" => -- bsr / jsr
null;
when "1110" => -- ldx
case pre_code is
when "00010000" => -- page 2 -- ldy
left_ctrl <= iy_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
iy_ctrl <= load_iy;
when others => -- page 1 -- ldx
left_ctrl <= ix_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
ix_ctrl <= load_ix;
end case;
when "1111" => -- stx
case pre_code is
when "00010000" => -- page 2 -- sty
left_ctrl <= iy_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
when others => -- page 1 -- stx
left_ctrl <= ix_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
end case;
when others =>
null;
end case;
when "11" => -- accb dual op
case op_code(3 downto 0) is
when "0000" => -- subb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub8;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "0001" => -- cmpb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub8;
cc_ctrl <= load_cc;
when "0010" => -- sbcb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sbc;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "0011" => -- addd
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_add16;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
when "0100" => -- andb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_and;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "0101" => -- bitb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_and;
cc_ctrl <= load_cc;
when "0110" => -- ldab
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld8;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "0111" => -- stab
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st8;
cc_ctrl <= load_cc;
when "1000" => -- eorb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_eor;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "1001" => -- adcb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_adc;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "1010" => -- orab
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ora;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "1011" => -- addb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_add8;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "1100" => -- ldd
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
when "1101" => -- std
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
when "1110" => -- ldu
case pre_code is
when "00010000" => -- page 2 -- lds
left_ctrl <= sp_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
sp_ctrl <= load_sp;
when others => -- page 1 -- ldu
left_ctrl <= up_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
up_ctrl <= load_up;
end case;
when "1111" =>
case pre_code is
when "00010000" => -- page 2 -- sts
left_ctrl <= sp_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
when others => -- page 1 -- stu
left_ctrl <= up_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
end case;
when others =>
null;
end case;
when others =>
null;
end case;
 
end if; -- first instruction cycle (fic)
lic_out <= lic;
end process;
 
end rtl;
/trunk/rtl/VHDL/cpu09m.vhd
0,0 → 1,5921
--===========================================================================--
-- --
-- Synthesizable 6809 instruction compatible VHDL CPU core --
-- --
--===========================================================================--
--
-- File name : cpu09m.vhd
--
-- Entity name : cpu09
--
-- Purpose : 6809 instruction compatible CPU core written in VHDL
-- with Last Instruction Cycle, bus available, bus status,
-- and instruction fetch signals.
-- Not cycle compatible with the original 6809 CPU
--
-- Dependencies : ieee.std_logic_1164
-- ieee.std_logic_unsigned
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- Description : VMA (valid memory address) is hight whenever a valid memory
-- access is made by an instruction fetch, interrupt vector fetch
-- or a data read or write otherwise it is low indicating an idle
-- bus cycle.
-- IFETCH (instruction fetch output) is high whenever an
-- instruction byte is read i.e. the program counter is applied
-- to the address bus.
-- LIC (last instruction cycle output) is normally low
-- but goes high on the last cycle of an instruction.
-- BA (bus available output) is normally low but goes high while
-- waiting in a Sync instruction state or the CPU is halted
-- i.e. a DMA grant.
-- BS (bus status output) is normally low but goes high during an
-- interrupt or reset vector fetch or the processor is halted
-- i.e. a DMA grant.
--
-- Copyright (C) 2003 - 2010 John Kent
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program 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 General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
--===========================================================================--
-- --
-- Revision History --
-- --
--===========================================================================--
--
-- Version 0.1 - 26 June 2003 - John Kent
-- Added extra level in state stack
-- fixed some calls to the extended addressing state
--
-- Version 0.2 - 5 Sept 2003 - John Kent
-- Fixed 16 bit indexed offset (was doing read rather than fetch)
-- Added/Fixed STY and STS instructions.
-- ORCC_STATE ANDed CC state rather than ORed it - Now fixed
-- CMPX Loaded ACCA and ACCB - Now fixed
--
-- Version 1.0 - 6 Sep 2003 - John Kent
-- Initial release to Open Cores
-- reversed clock edge
--
-- Version 1.1 - 29 November 2003 John kent
-- ACCA and ACCB indexed offsets are 2's complement.
-- ALU Right Mux now sign extends ACCA & ACCB offsets
-- Absolute Indirect addressing performed a read on the
-- second byte of the address rather than a fetch
-- so it formed an incorrect address. Now fixed.
--
-- Version 1.2 - 29 November 2003 John Kent
-- LEAX and LEAY affect the Z bit only
-- LEAS and LEAU do not affect any condition codes
-- added an extra ALU control for LEA.
--
-- Version 1.3 - 12 December 2003 John Kent
-- CWAI did not work, was missed a PUSH_ST on calling
-- the ANDCC_STATE. Thanks go to Ghassan Kraidy for
-- finding this fault.
--
-- Version 1.4 - 12 December 2003 John Kent
-- Missing cc_ctrl assignment in otherwise case of
-- lea_state resulted in cc_ctrl being latched in
-- that state.
-- The otherwise statement should never be reached,
-- and has been fixed simply to resolve synthesis warnings.
--
-- Version 1.5 - 17 january 2004 John kent
-- The clear instruction used "alu_ld8" to control the ALU
-- rather than "alu_clr". This mean the Carry was not being
-- cleared correctly.
--
-- Version 1.6 - 24 January 2004 John Kent
-- Fixed problems in PSHU instruction
--
-- Version 1.7 - 25 January 2004 John Kent
-- removed redundant "alu_inx" and "alu_dex'
-- Removed "test_alu" and "test_cc"
-- STD instruction did not set condition codes
-- JMP direct was not decoded properly
-- CLR direct performed an unwanted read cycle
-- Bogus "latch_md" in Page2 indexed addressing
--
-- Version 1.8 - 27 January 2004 John Kent
-- CWAI in decode1_state should increment the PC.
-- ABX is supposed to be an unsigned addition.
-- Added extra ALU function
-- ASR8 slightly changed in the ALU.
--
-- Version 1.9 - 20 August 2005
-- LSR8 is now handled in ASR8 and ROR8 case in the ALU,
-- rather than LSR16. There was a problem with single
-- operand instructions using the MD register which is
-- sign extended on the first 8 bit fetch.
--
-- Version 1.10 - 13 September 2005
-- TFR & EXG instructions did not work for the Condition Code Register
-- An extra case has been added to the ALU for the alu_tfr control
-- to assign the left ALU input (alu_left) to the condition code
-- outputs (cc_out).
--
-- Version 1.11 - 16 September 2005
-- JSR ,X should not predecrement S before calculating the jump address.
-- The reason is that JSR [0,S] needs S to point to the top of the stack
-- to fetch a valid vector address. The solution is to have the addressing
-- mode microcode called before decrementing S and then decrementing S in
-- JSR_STATE. JSR_STATE in turn calls PUSH_RETURN_LO_STATE rather than
-- PUSH_RETURN_HI_STATE so that both the High & Low halves of the PC are
-- pushed on the stack. This adds one extra bus cycle, but resolves the
-- addressing conflict. I've also removed the pre-decement S in
-- JSR EXTENDED as it also calls JSR_STATE.
--
-- Version 1.12 - 6th June 2006
-- 6809 Programming reference manual says V is not affected by ASR, LSR and ROR
-- This is different to the 6800. CLR should reset the V bit.
--
-- Version 1.13 - 7th July 2006
-- Disable NMI on reset until S Stack pointer has been loaded.
-- Added nmi_enable signal in sp_reg process and nmi_handler process.
--
-- Version 1.14 - 11th July 2006
-- 1. Added new state to RTI called rti_entire_state.
-- This state tests the CC register after it has been loaded
-- from the stack. Previously the current CC was tested which
-- was incorrect. The Entire Flag should be set before the
-- interrupt stacks the CC.
-- 2. On bogus Interrupts, int_cc_state went to rti_state,
-- which was an enumerated state, but not defined anywhere.
-- rti_state has been changed to rti_cc_state so that bogus interrupt
-- will perform an RTI after entering that state.
-- 3. Sync should generate an interrupt if the interrupt masks
-- are cleared. If the interrupt masks are set, then an interrupt
-- will cause the the PC to advance to the next instruction.
-- Note that I don't wait for an interrupt to be asserted for
-- three clock cycles.
-- 4. Added new ALU control state "alu_mul". "alu_mul" is used in
-- the Multiply instruction replacing "alu_add16". This is similar
-- to "alu_add16" except it sets the Carry bit to B7 of the result
-- in ACCB, sets the Zero bit if the 16 bit result is zero, but
-- does not affect The Half carry (H), Negative (N) or Overflow (V)
-- flags. The logic was re-arranged so that it adds md or zero so
-- that the Carry condition code is set on zero multiplicands.
-- 5. DAA (Decimal Adjust Accumulator) should set the Negative (N)
-- and Zero Flags. It will also affect the Overflow (V) flag although
-- the operation is undefined. It's anyones guess what DAA does to V.
--
-- Version 1.15 - 25th Feb 2007 - John Kent
-- line 9672 changed "if Halt <= '1' then" to "if Halt = '1' then"
-- Changed sensitivity lists.
--
-- Version 1.16 - 5th February 2008 - John Kent
-- FIRQ interrupts should take priority over IRQ Interrupts.
-- This presumably means they should be tested for before IRQ
-- when they happen concurrently.
--
-- Version 1.17 - 18th February 2008 - John Kent
-- NMI in CWAI should mask IRQ and FIRQ interrupts
--
-- Version 1.18 - 21st February 2008 - John Kent
-- Removed default register settings in each case statement
-- and placed them at the beginning of the state sequencer.
-- Modified the SYNC instruction so that the interrupt vector(iv)
-- is not set unless an unmasked FIRQ or IRQ is received.
--
-- Version 1.19 - 25th February 2008 - John Kent
-- Enumerated separate states for FIRQ/FAST and NMIIRQ/ENTIRE
-- Enumerated separate states for MASKI and MASKIF states
-- Removed code on BSR/JSR in fetch cycle
--
-- Version 1.20 - 8th October 2011 - John Kent
-- added fetch output which should go high during the fetch cycle
--
-- Version 1.21 - 8th October 2011 - John Kent
-- added Last Instruction Cycle signal
-- replaced fetch with ifetch (instruction fetch) signal
-- added ba & bs (bus available & bus status) signals
--
-- Version 1.22 - 2011-10-29 John Kent
-- The halt state isn't correct.
-- The halt state is entered into from the fetch_state
-- It returned to the fetch state which may re-run an execute cycle
-- on the accumulator and it won't necessarily be the last instruction cycle
-- I've changed the halt state to return to the decode1_state
--
-- Version 1.23 - 2011-10-30 John Kent
-- sample halt in the change_state process if lic is high (last instruction cycle)
--
-- Version 1.24 - 2011-11-01 John Kent
-- Handle interrupts in change_state process
-- Sample interrupt inputs on last instruction cycle
-- Remove iv_ctrl and implement iv (interrupt vector) in change_state process.
-- Generate fic (first instruction cycle) from lic (last instruction cycle)
-- and use it to complete the dual operand execute cycle before servicing
-- halt or interrupts requests.
-- rename lic to lic_out on the entity declaration so that lic can be tested internally.
-- add int_firq1_state and int_nmirq1_state to allow for the dual operand execute cycle
-- integrated nmi_ctrl into change_state process
-- Reduces the microcode state stack to one entry (saved_state)
-- imm16_state jumps directly to the fetch_state
-- pull_return_lo states jumps directly to the fetch_state
-- duplicate andcc_state as cwai_state
-- rename exg1_state as exg2 state and duplicate tfr_state as exg1_state
--
-- Version 1.25 - 2011-11-27 John Kent
-- Changed the microcode for saving registers on an interrupt into a microcode subroutine.
-- Removed SWI servicing from the change state process and made SWI, SWI2 & SWI3
-- call the interrupt microcode subroutine.
-- Added additional states for nmi, and irq for interrupt servicing.
-- Added additional states for nmi/irq, firq, and swi interrupts to mask I & F flags.
--
-- Version 1.26 - 2013-03-18 John Kent
-- pre-initialized cond_true variable to true in state sequencer
-- re-arranged change_state process slightly
--
-- Version 1.27 - 2015-05-30 John Kent
-- Added test in state machine for masked IRQ and FIRQ in Sync_state.
--
-- Version 1.28 - 2015-05-30 John Kent.
-- Moved IRQ and FIRQ test from state machine to the state sequencer Sync_state.
--
-- Version 1.29 - 2017-02-11 John Kent
-- Make MUL 11 cycles long rather than 13 cycles.
-- 1 fetch_state, 2 decode1_state,
-- 3 mul_state, 4 mulea_state, 5 muld_state
-- 6 mul0_state, 7 mul1_state, 8 mul2_state, 9 mul3_state,
-- 10 mul4_state, 11 mul5_state, 12 mul6_state, 13 mul7_state,
-- move mul_state into decode1_state
-- move mul7_state into fetch_state
--
-- Version 1.29 - 2017-03-08 John Kent.
-- Moved LIC in ABX ?
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity cpu09 is
port (
clk : in std_logic; -- E clock input (falling edge)
rst : in std_logic; -- reset input (active high)
vma : out std_logic; -- valid memory address (active high)
lic_out : out std_logic; -- last instruction cycle (active high)
ifetch : out std_logic; -- instruction fetch cycle (active high)
opfetch : out std_logic; -- opcode fetch (active high)
ba : out std_logic; -- bus available (high on sync wait or DMA grant)
bs : out std_logic; -- bus status (high on interrupt or reset vector fetch or DMA grant)
addr : out std_logic_vector(15 downto 0); -- address bus output
rw : out std_logic; -- read not write output
data_out : out std_logic_vector(7 downto 0); -- data bus output
data_in : in std_logic_vector(7 downto 0); -- data bus input
irq : in std_logic; -- interrupt request input (active high)
firq : in std_logic; -- fast interrupt request input (active high)
nmi : in std_logic; -- non maskable interrupt request input (active high)
halt : in std_logic; -- halt input (active high) grants DMA
hold : in std_logic -- hold input (active high) extend bus cycle
);
end cpu09;
 
architecture rtl of cpu09 is
 
constant EBIT : integer := 7;
constant FBIT : integer := 6;
constant HBIT : integer := 5;
constant IBIT : integer := 4;
constant NBIT : integer := 3;
constant ZBIT : integer := 2;
constant VBIT : integer := 1;
constant CBIT : integer := 0;
 
--
-- Interrupt vector modifiers
--
constant RST_VEC : std_logic_vector(2 downto 0) := "111";
constant NMI_VEC : std_logic_vector(2 downto 0) := "110";
constant SWI_VEC : std_logic_vector(2 downto 0) := "101";
constant IRQ_VEC : std_logic_vector(2 downto 0) := "100";
constant FIRQ_VEC : std_logic_vector(2 downto 0) := "011";
constant SWI2_VEC : std_logic_vector(2 downto 0) := "010";
constant SWI3_VEC : std_logic_vector(2 downto 0) := "001";
constant RESV_VEC : std_logic_vector(2 downto 0) := "000";
 
type state_type is (-- Start off in Reset
reset_state,
-- Fetch Interrupt Vectors (including reset)
vect_lo_state, vect_hi_state, vect_idle_state,
-- Fetch Instruction Cycle
fetch_state,
-- Decode Instruction Cycles
decode1_state, decode2_state, decode3_state,
-- Calculate Effective Address
imm16_state,
indexed_state, index8_state, index16_state, index16_2_state,
pcrel8_state, pcrel16_state, pcrel16_2_state,
indexaddr_state, indexaddr2_state,
postincr1_state, postincr2_state,
indirect_state, indirect2_state, indirect3_state,
extended_state,
-- single ops
single_op_read_state,
single_op_exec_state,
single_op_write_state,
-- Dual op states
dual_op_read8_state, dual_op_read16_state, dual_op_read16_2_state,
dual_op_write8_state, dual_op_write16_state,
--
sync_state, halt_state, cwai_state,
--
andcc_state, orcc_state,
tfr_state,
exg_state, exg1_state, exg2_state,
lea_state,
-- Multiplication
mulea_state, muld_state,
mul0_state, mul1_state, mul2_state, mul3_state,
mul4_state, mul5_state, mul6_state,
-- Branches
lbranch_state, sbranch_state,
-- Jumps, Subroutine Calls and Returns
jsr_state, jmp_state,
push_return_hi_state, push_return_lo_state,
pull_return_hi_state, pull_return_lo_state,
-- Interrupt cycles
int_nmi_state, int_nmi1_state,
int_irq_state, int_irq1_state,
int_firq_state, int_firq1_state,
int_entire_state, int_fast_state,
int_pcl_state, int_pch_state,
int_upl_state, int_uph_state,
int_iyl_state, int_iyh_state,
int_ixl_state, int_ixh_state,
int_dp_state,
int_accb_state, int_acca_state,
int_cc_state,
int_cwai_state,
int_nmimask_state, int_firqmask_state, int_swimask_state, int_irqmask_state,
-- Return From Interrupt
rti_cc_state, rti_entire_state,
rti_acca_state, rti_accb_state,
rti_dp_state,
rti_ixl_state, rti_ixh_state,
rti_iyl_state, rti_iyh_state,
rti_upl_state, rti_uph_state,
rti_pcl_state, rti_pch_state,
-- Push Registers using SP
pshs_state,
pshs_pcl_state, pshs_pch_state,
pshs_upl_state, pshs_uph_state,
pshs_iyl_state, pshs_iyh_state,
pshs_ixl_state, pshs_ixh_state,
pshs_dp_state,
pshs_acca_state, pshs_accb_state,
pshs_cc_state,
-- Pull Registers using SP
puls_state,
puls_cc_state,
puls_acca_state, puls_accb_state,
puls_dp_state,
puls_ixl_state, puls_ixh_state,
puls_iyl_state, puls_iyh_state,
puls_upl_state, puls_uph_state,
puls_pcl_state, puls_pch_state,
-- Push Registers using UP
pshu_state,
pshu_pcl_state, pshu_pch_state,
pshu_spl_state, pshu_sph_state,
pshu_iyl_state, pshu_iyh_state,
pshu_ixl_state, pshu_ixh_state,
pshu_dp_state,
pshu_acca_state, pshu_accb_state,
pshu_cc_state,
-- Pull Registers using UP
pulu_state,
pulu_cc_state,
pulu_acca_state, pulu_accb_state,
pulu_dp_state,
pulu_ixl_state, pulu_ixh_state,
pulu_iyl_state, pulu_iyh_state,
pulu_spl_state, pulu_sph_state,
pulu_pcl_state, pulu_pch_state );
 
type st_type is (reset_st, push_st, idle_st );
type iv_type is (latch_iv, swi3_iv, swi2_iv, firq_iv, irq_iv, swi_iv, nmi_iv, reset_iv);
type addr_type is (idle_ad, fetch_ad, read_ad, write_ad, pushu_ad, pullu_ad, pushs_ad, pulls_ad, int_hi_ad, int_lo_ad );
type dout_type is (cc_dout, acca_dout, accb_dout, dp_dout,
ix_lo_dout, ix_hi_dout, iy_lo_dout, iy_hi_dout,
up_lo_dout, up_hi_dout, sp_lo_dout, sp_hi_dout,
pc_lo_dout, pc_hi_dout, md_lo_dout, md_hi_dout );
type op_type is (reset_op, fetch_op, latch_op );
type pre_type is (reset_pre, fetch_pre, latch_pre );
type cc_type is (reset_cc, load_cc, pull_cc, latch_cc );
type acca_type is (reset_acca, load_acca, load_hi_acca, pull_acca, latch_acca );
type accb_type is (reset_accb, load_accb, pull_accb, latch_accb );
type dp_type is (reset_dp, load_dp, pull_dp, latch_dp );
type ix_type is (reset_ix, load_ix, pull_lo_ix, pull_hi_ix, latch_ix );
type iy_type is (reset_iy, load_iy, pull_lo_iy, pull_hi_iy, latch_iy );
type sp_type is (reset_sp, latch_sp, load_sp, pull_hi_sp, pull_lo_sp );
type up_type is (reset_up, latch_up, load_up, pull_hi_up, pull_lo_up );
type pc_type is (reset_pc, latch_pc, load_pc, pull_lo_pc, pull_hi_pc, incr_pc );
type md_type is (reset_md, latch_md, load_md, fetch_first_md, fetch_next_md, shiftl_md );
type ea_type is (reset_ea, latch_ea, load_ea, fetch_first_ea, fetch_next_ea );
type left_type is (cc_left, acca_left, accb_left, dp_left,
ix_left, iy_left, up_left, sp_left,
accd_left, md_left, pc_left, ea_left );
type right_type is (ea_right, zero_right, one_right, two_right,
acca_right, accb_right, accd_right,
md_right, md_sign5_right, md_sign8_right );
type alu_type is (alu_add8, alu_sub8, alu_add16, alu_sub16, alu_adc, alu_sbc,
alu_and, alu_ora, alu_eor,
alu_tst, alu_inc, alu_dec, alu_clr, alu_neg, alu_com,
alu_lsr16, alu_lsl16,
alu_ror8, alu_rol8, alu_mul,
alu_asr8, alu_asl8, alu_lsr8,
alu_andcc, alu_orcc, alu_sex, alu_tfr, alu_abx,
alu_seif, alu_sei, alu_see, alu_cle,
alu_ld8, alu_st8, alu_ld16, alu_st16, alu_lea, alu_nop, alu_daa );
 
signal op_code: std_logic_vector(7 downto 0);
signal pre_code: std_logic_vector(7 downto 0);
signal acca: std_logic_vector(7 downto 0);
signal accb: std_logic_vector(7 downto 0);
signal cc: std_logic_vector(7 downto 0);
signal cc_out: std_logic_vector(7 downto 0);
signal dp: std_logic_vector(7 downto 0);
signal xreg: std_logic_vector(15 downto 0);
signal yreg: std_logic_vector(15 downto 0);
signal sp: std_logic_vector(15 downto 0);
signal up: std_logic_vector(15 downto 0);
signal ea: std_logic_vector(15 downto 0);
signal pc: std_logic_vector(15 downto 0);
signal md: std_logic_vector(15 downto 0);
signal left: std_logic_vector(15 downto 0);
signal right: std_logic_vector(15 downto 0);
signal out_alu: std_logic_vector(15 downto 0);
signal iv: std_logic_vector(2 downto 0);
signal nmi_req: std_logic;
signal nmi_ack: std_logic;
signal nmi_enable: std_logic;
signal fic: std_logic; -- first instruction cycle
signal lic: std_logic; -- last instruction cycle
 
signal state: state_type;
signal next_state: state_type;
signal return_state: state_type;
signal saved_state: state_type;
signal st_ctrl: st_type;
signal iv_ctrl: iv_type;
signal pc_ctrl: pc_type;
signal ea_ctrl: ea_type;
signal op_ctrl: op_type;
signal pre_ctrl: pre_type;
signal md_ctrl: md_type;
signal acca_ctrl: acca_type;
signal accb_ctrl: accb_type;
signal ix_ctrl: ix_type;
signal iy_ctrl: iy_type;
signal cc_ctrl: cc_type;
signal dp_ctrl: dp_type;
signal sp_ctrl: sp_type;
signal up_ctrl: up_type;
signal left_ctrl: left_type;
signal right_ctrl: right_type;
signal alu_ctrl: alu_type;
signal addr_ctrl: addr_type;
signal dout_ctrl: dout_type;
 
 
begin
 
----------------------------------
--
-- State machine stack
--
----------------------------------
--state_stack_proc: process( clk, hold, state_stack, st_ctrl,
-- return_state, fetch_state )
state_stack_proc: process( clk, st_ctrl, return_state )
begin
if clk'event and clk = '0' then
if hold = '0' then
case st_ctrl is
when reset_st =>
saved_state <= fetch_state;
when push_st =>
saved_state <= return_state;
when others =>
null;
end case;
end if;
end if;
end process;
 
----------------------------------
--
-- Interrupt Vector control
--
----------------------------------
--
int_vec_proc: process( clk, iv_ctrl )
begin
if clk'event and clk = '0' then
if hold = '0' then
case iv_ctrl is
when reset_iv =>
iv <= RST_VEC;
when nmi_iv =>
iv <= NMI_VEC;
when swi_iv =>
iv <= SWI_VEC;
when irq_iv =>
iv <= IRQ_VEC;
when firq_iv =>
iv <= FIRQ_VEC;
when swi2_iv =>
iv <= SWI2_VEC;
when swi3_iv =>
iv <= SWI3_VEC;
when others =>
null;
end case;
end if; -- hold
end if; -- clk
end process;
----------------------------------
--
-- Program Counter Control
--
----------------------------------
 
--pc_reg: process( clk, pc_ctrl, hold, pc, out_alu, data_in )
pc_reg: process( clk )
begin
if clk'event and clk = '0' then
if hold = '0' then
case pc_ctrl is
when reset_pc =>
pc <= (others=>'0');
when load_pc =>
pc <= out_alu(15 downto 0);
when pull_lo_pc =>
pc(7 downto 0) <= data_in;
when pull_hi_pc =>
pc(15 downto 8) <= data_in;
when incr_pc =>
pc <= pc + 1;
when others =>
null;
end case;
end if;
end if;
end process;
 
----------------------------------
--
-- Effective Address Control
--
----------------------------------
 
--ea_reg: process( clk, ea_ctrl, hold, ea, out_alu, data_in, dp )
ea_reg: process( clk )
begin
 
if clk'event and clk = '0' then
if hold= '0' then
case ea_ctrl is
when reset_ea =>
ea <= (others=>'0');
when fetch_first_ea =>
ea(7 downto 0) <= data_in;
ea(15 downto 8) <= dp;
when fetch_next_ea =>
ea(15 downto 8) <= ea(7 downto 0);
ea(7 downto 0) <= data_in;
when load_ea =>
ea <= out_alu(15 downto 0);
when others =>
null;
end case;
end if;
end if;
end process;
 
--------------------------------
--
-- Accumulator A
--
--------------------------------
--acca_reg : process( clk, acca_ctrl, hold, out_alu, acca, data_in )
acca_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold = '0' then
case acca_ctrl is
when reset_acca =>
acca <= (others=>'0');
when load_acca =>
acca <= out_alu(7 downto 0);
when load_hi_acca =>
acca <= out_alu(15 downto 8);
when pull_acca =>
acca <= data_in;
when others =>
null;
end case;
end if;
end if;
end process;
 
--------------------------------
--
-- Accumulator B
--
--------------------------------
--accb_reg : process( clk, accb_ctrl, hold, out_alu, accb, data_in )
accb_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold = '0' then
case accb_ctrl is
when reset_accb =>
accb <= (others=>'0');
when load_accb =>
accb <= out_alu(7 downto 0);
when pull_accb =>
accb <= data_in;
when others =>
null;
end case;
end if;
end if;
end process;
 
--------------------------------
--
-- X Index register
--
--------------------------------
--ix_reg : process( clk, ix_ctrl, hold, out_alu, xreg, data_in )
ix_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold = '0' then
case ix_ctrl is
when reset_ix =>
xreg <= (others=>'0');
when load_ix =>
xreg <= out_alu(15 downto 0);
when pull_hi_ix =>
xreg(15 downto 8) <= data_in;
when pull_lo_ix =>
xreg(7 downto 0) <= data_in;
when others =>
null;
end case;
end if;
end if;
end process;
 
--------------------------------
--
-- Y Index register
--
--------------------------------
--iy_reg : process( clk, iy_ctrl, hold, out_alu, yreg, data_in )
iy_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold = '0' then
case iy_ctrl is
when reset_iy =>
yreg <= (others=>'0');
when load_iy =>
yreg <= out_alu(15 downto 0);
when pull_hi_iy =>
yreg(15 downto 8) <= data_in;
when pull_lo_iy =>
yreg(7 downto 0) <= data_in;
when others =>
null;
end case;
end if;
end if;
end process;
 
--------------------------------
--
-- S stack pointer
--
--------------------------------
--sp_reg : process( clk, sp_ctrl, hold, sp, out_alu, data_in, nmi_enable )
sp_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold = '0' then
case sp_ctrl is
when reset_sp =>
sp <= (others=>'0');
nmi_enable <= '0';
when load_sp =>
sp <= out_alu(15 downto 0);
nmi_enable <= '1';
when pull_hi_sp =>
sp(15 downto 8) <= data_in;
when pull_lo_sp =>
sp(7 downto 0) <= data_in;
nmi_enable <= '1';
when others =>
null;
end case;
end if;
end if;
end process;
 
--------------------------------
--
-- U stack pointer
--
--------------------------------
--up_reg : process( clk, up_ctrl, hold, up, out_alu, data_in )
up_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold = '0' then
case up_ctrl is
when reset_up =>
up <= (others=>'0');
when load_up =>
up <= out_alu(15 downto 0);
when pull_hi_up =>
up(15 downto 8) <= data_in;
when pull_lo_up =>
up(7 downto 0) <= data_in;
when others =>
null;
end case;
end if;
end if;
end process;
 
--------------------------------
--
-- Memory Data
--
--------------------------------
--md_reg : process( clk, md_ctrl, hold, out_alu, data_in, md )
md_reg : process( clk )
begin
if clk'event and clk = '0' then
if hold = '0' then
case md_ctrl is
when reset_md =>
md <= (others=>'0');
when load_md =>
md <= out_alu(15 downto 0);
when fetch_first_md => -- sign extend md for branches
md(15 downto 8) <= data_in(7) & data_in(7) & data_in(7) & data_in(7) &
data_in(7) & data_in(7) & data_in(7) & data_in(7) ;
md(7 downto 0) <= data_in;
when fetch_next_md =>
md(15 downto 8) <= md(7 downto 0);
md(7 downto 0) <= data_in;
when shiftl_md =>
md(15 downto 1) <= md(14 downto 0);
md(0) <= '0';
when others =>
null;
end case;
end if;
end if;
end process;
 
 
----------------------------------
--
-- Condition Codes
--
----------------------------------
 
--cc_reg: process( clk, cc_ctrl, hold, cc_out, cc, data_in )
cc_reg: process( clk )
begin
if clk'event and clk = '0' then
if hold = '0' then
case cc_ctrl is
when reset_cc =>
cc <= "11010000"; -- set EBIT, FBIT & IBIT
when load_cc =>
cc <= cc_out;
when pull_cc =>
cc <= data_in;
when others =>
null;
end case;
end if;
end if;
end process;
 
----------------------------------
--
-- Direct Page register
--
----------------------------------
 
--dp_reg: process( clk, dp_ctrl, hold, out_alu, dp, data_in )
dp_reg: process( clk )
begin
if clk'event and clk = '0' then
if hold = '0' then
case dp_ctrl is
when reset_dp =>
dp <= (others=>'0');
when load_dp =>
dp <= out_alu(7 downto 0);
when pull_dp =>
dp <= data_in;
when others =>
null;
end case;
end if;
end if;
end process;
 
 
----------------------------------
--
-- op code register
--
----------------------------------
 
--op_reg: process( clk, op_ctrl, hold, op_code, data_in )
op_reg: process( clk )
begin
if clk'event and clk = '0' then
if hold = '0' then
case op_ctrl is
when reset_op =>
op_code <= "00010010";
when fetch_op =>
op_code <= data_in;
when others =>
null;
end case;
end if;
end if;
end process;
 
 
----------------------------------
--
-- pre byte op code register
--
----------------------------------
 
--pre_reg: process( clk, pre_ctrl, hold, pre_code, data_in )
pre_reg: process( clk )
begin
if clk'event and clk = '0' then
if hold = '0' then
case pre_ctrl is
when reset_pre =>
pre_code <= (others=>'0');
when fetch_pre =>
pre_code <= data_in;
when others =>
null;
end case;
end if;
end if;
end process;
 
--------------------------------
--
-- state machine
--
--------------------------------
 
--change_state: process( clk, rst, state, hold, next_state )
change_state: process( clk )
begin
if clk'event and clk = '0' then
if rst = '1' then
fic <= '0';
nmi_ack <= '0';
state <= reset_state;
elsif hold = '0' then
fic <= lic;
--
-- nmi request is not cleared until nmi input goes low
--
if (nmi_req = '0') and (nmi_ack='1') then
nmi_ack <= '0';
end if;
if (nmi_req = '1') and (nmi_ack = '0') and (state = int_nmimask_state) then
nmi_ack <= '1';
end if;
 
if lic = '1' then
if halt = '1' then
state <= halt_state;
-- service non maskable interrupts
elsif (nmi_req = '1') and (nmi_ack = '0') then
state <= int_nmi_state;
--
-- FIRQ & IRQ are level sensitive
--
elsif (firq = '1') and (cc(FBIT) = '0') then
state <= int_firq_state;
 
elsif (irq = '1') and (cc(IBIT) = '0') then
state <= int_irq_state;
--
-- Version 1.27 2015-05-30
-- Exit sync_state on masked interrupt.
--
-- Version 1.28 2015-05-30
-- Move this code to the state sequencer
-- near line 5566.
--
-- elsif (state = sync_state) and ((firq = '1') or (irq = '1'))then
-- state <= fetch_state;
--
else
state <= next_state;
end if; -- halt, nmi, firq, irq
else
state <= next_state;
end if; -- lic
end if; -- reset/hold
end if; -- clk
end process;
------------------------------------
--
-- Detect Edge of NMI interrupt
--
------------------------------------
 
--nmi_handler : process( clk, rst, nmi, nmi_ack, nmi_req, nmi_enable )
nmi_handler : process( rst, clk )
begin
if rst='1' then
nmi_req <= '0';
elsif clk'event and clk='0' then
if (nmi='1') and (nmi_ack='0') and (nmi_enable='1') then
nmi_req <= '1';
else
if (nmi='0') and (nmi_ack='1') then
nmi_req <= '0';
end if;
end if;
end if;
end process;
 
 
----------------------------------
--
-- Address output multiplexer
--
----------------------------------
 
addr_mux: process( addr_ctrl, pc, ea, up, sp, iv )
begin
ifetch <= '0';
vma <= '1';
case addr_ctrl is
when fetch_ad =>
addr <= pc;
rw <= '1';
ifetch <= '1';
when read_ad =>
addr <= ea;
rw <= '1';
when write_ad =>
addr <= ea;
rw <= '0';
when pushs_ad =>
addr <= sp;
rw <= '0';
when pulls_ad =>
addr <= sp;
rw <= '1';
when pushu_ad =>
addr <= up;
rw <= '0';
when pullu_ad =>
addr <= up;
rw <= '1';
when int_hi_ad =>
addr <= "111111111111" & iv & "0";
rw <= '1';
when int_lo_ad =>
addr <= "111111111111" & iv & "1";
rw <= '1';
when others =>
addr <= "1111111111111111";
rw <= '1';
vma <= '0';
end case;
end process;
 
--------------------------------
--
-- Data Bus output
--
--------------------------------
dout_mux : process( dout_ctrl, md, acca, accb, dp, xreg, yreg, sp, up, pc, cc )
begin
case dout_ctrl is
when cc_dout => -- condition code register
data_out <= cc;
when acca_dout => -- accumulator a
data_out <= acca;
when accb_dout => -- accumulator b
data_out <= accb;
when dp_dout => -- direct page register
data_out <= dp;
when ix_lo_dout => -- X index reg
data_out <= xreg(7 downto 0);
when ix_hi_dout => -- X index reg
data_out <= xreg(15 downto 8);
when iy_lo_dout => -- Y index reg
data_out <= yreg(7 downto 0);
when iy_hi_dout => -- Y index reg
data_out <= yreg(15 downto 8);
when up_lo_dout => -- U stack pointer
data_out <= up(7 downto 0);
when up_hi_dout => -- U stack pointer
data_out <= up(15 downto 8);
when sp_lo_dout => -- S stack pointer
data_out <= sp(7 downto 0);
when sp_hi_dout => -- S stack pointer
data_out <= sp(15 downto 8);
when md_lo_dout => -- alu output
data_out <= md(7 downto 0);
when md_hi_dout => -- alu output
data_out <= md(15 downto 8);
when pc_lo_dout => -- low order pc
data_out <= pc(7 downto 0);
when pc_hi_dout => -- high order pc
data_out <= pc(15 downto 8);
end case;
end process;
 
----------------------------------
--
-- Left Mux
--
----------------------------------
 
left_mux: process( left_ctrl, acca, accb, cc, dp, xreg, yreg, up, sp, pc, ea, md )
begin
case left_ctrl is
when cc_left =>
left(15 downto 8) <= "00000000";
left(7 downto 0) <= cc;
when acca_left =>
left(15 downto 8) <= "00000000";
left(7 downto 0) <= acca;
when accb_left =>
left(15 downto 8) <= "00000000";
left(7 downto 0) <= accb;
when dp_left =>
left(15 downto 8) <= "00000000";
left(7 downto 0) <= dp;
when accd_left =>
left(15 downto 8) <= acca;
left(7 downto 0) <= accb;
when md_left =>
left <= md;
when ix_left =>
left <= xreg;
when iy_left =>
left <= yreg;
when sp_left =>
left <= sp;
when up_left =>
left <= up;
when pc_left =>
left <= pc;
when others =>
-- when ea_left =>
left <= ea;
end case;
end process;
 
----------------------------------
--
-- Right Mux
--
----------------------------------
 
right_mux: process( right_ctrl, md, acca, accb, ea )
begin
case right_ctrl is
when ea_right =>
right <= ea;
when zero_right =>
right <= "0000000000000000";
when one_right =>
right <= "0000000000000001";
when two_right =>
right <= "0000000000000010";
when acca_right =>
if acca(7) = '0' then
right <= "00000000" & acca(7 downto 0);
else
right <= "11111111" & acca(7 downto 0);
end if;
when accb_right =>
if accb(7) = '0' then
right <= "00000000" & accb(7 downto 0);
else
right <= "11111111" & accb(7 downto 0);
end if;
when accd_right =>
right <= acca & accb;
when md_sign5_right =>
if md(4) = '0' then
right <= "00000000000" & md(4 downto 0);
else
right <= "11111111111" & md(4 downto 0);
end if;
when md_sign8_right =>
if md(7) = '0' then
right <= "00000000" & md(7 downto 0);
else
right <= "11111111" & md(7 downto 0);
end if;
when others =>
-- when md_right =>
right <= md;
end case;
end process;
 
----------------------------------
--
-- Arithmetic Logic Unit
--
----------------------------------
 
alu: process( alu_ctrl, cc, left, right, out_alu, cc_out )
variable valid_lo, valid_hi : boolean;
variable carry_in : std_logic;
variable daa_reg : std_logic_vector(7 downto 0);
begin
 
case alu_ctrl is
when alu_adc | alu_sbc |
alu_rol8 | alu_ror8 =>
carry_in := cc(CBIT);
when alu_asr8 =>
carry_in := left(7);
when others =>
carry_in := '0';
end case;
 
valid_lo := left(3 downto 0) <= 9;
valid_hi := left(7 downto 4) <= 9;
 
--
-- CBIT HBIT VHI VLO DAA
-- 0 0 0 0 66 (!VHI : hi_nybble>8)
-- 0 0 0 1 60
-- 0 0 1 1 00
-- 0 0 1 0 06 ( VHI : hi_nybble<=8)
--
-- 0 1 1 0 06
-- 0 1 1 1 06
-- 0 1 0 1 66
-- 0 1 0 0 66
--
-- 1 1 0 0 66
-- 1 1 0 1 66
-- 1 1 1 1 66
-- 1 1 1 0 66
--
-- 1 0 1 0 66
-- 1 0 1 1 60
-- 1 0 0 1 60
-- 1 0 0 0 66
--
-- 66 = (!VHI & !VLO) + (CBIT & HBIT) + (HBIT & !VHI) + (CBIT & !VLO)
-- = (CBIT & (HBIT + !VLO)) + (!VHI & (HBIT + !VLO))
-- = (!VLO & (CBIT + !VHI)) + (HBIT & (CBIT + !VHI))
-- 60 = (CBIT & !HBIT & VLO) + (!HBIT & !VHI & VLO)
-- = (!HBIT & VLO & (CBIT + !VHI))
-- 06 = (!CBIT & VHI & (!VLO + VHI)
-- 00 = (!CBIT & !HBIT & VHI & VLO)
--
if (cc(CBIT) = '0') then
-- CBIT=0
if( cc(HBIT) = '0' ) then
-- HBIT=0
if valid_lo then
-- lo <= 9 (no overflow in low nybble)
if valid_hi then
-- hi <= 9 (no overflow in either low or high nybble)
daa_reg := "00000000";
else
-- hi > 9 (overflow in high nybble only)
daa_reg := "01100000";
end if;
else
-- lo > 9 (overflow in low nybble)
--
-- since there is already an overflow in the low nybble
-- you need to make room in the high nybble for the low nybble carry
-- so compare the high nybble with 8 rather than 9
-- if the high nybble is 9 there will be an overflow on the high nybble
-- after the decimal adjust which means it will roll over to an invalid BCD digit
--
if( left(7 downto 4) <= 8 ) then
-- hi <= 8 (overflow in low nybble only)
daa_reg := "00000110";
else
-- hi > 8 (overflow in low and high nybble)
daa_reg := "01100110";
end if;
end if;
else
-- HBIT=1 (overflow in low nybble)
if valid_hi then
-- hi <= 9 (overflow in low nybble only)
daa_reg := "00000110";
else
-- hi > 9 (overflow in low and high nybble)
daa_reg := "01100110";
end if;
end if;
else
-- CBIT=1 (carry => overflow in high nybble)
if ( cc(HBIT) = '0' )then
-- HBIT=0 (half carry clear => may or may not be an overflow in the low nybble)
if valid_lo then
-- lo <=9 (overflow in high nybble only)
daa_reg := "01100000";
else
-- lo >9 (overflow in low and high nybble)
daa_reg := "01100110";
end if;
else
-- HBIT=1 (overflow in low and high nybble)
daa_reg := "01100110";
end if;
end if;
 
case alu_ctrl is
when alu_add8 | alu_inc |
alu_add16 | alu_adc | alu_mul =>
out_alu <= left + right + ("000000000000000" & carry_in);
when alu_sub8 | alu_dec |
alu_sub16 | alu_sbc =>
out_alu <= left - right - ("000000000000000" & carry_in);
when alu_abx =>
out_alu <= left + ("00000000" & right(7 downto 0)) ;
when alu_and =>
out_alu <= left and right; -- and/bit
when alu_ora =>
out_alu <= left or right; -- or
when alu_eor =>
out_alu <= left xor right; -- eor/xor
when alu_lsl16 | alu_asl8 | alu_rol8 =>
out_alu <= left(14 downto 0) & carry_in; -- rol8/asl8/lsl16
when alu_lsr16 =>
out_alu <= carry_in & left(15 downto 1); -- lsr16
when alu_lsr8 | alu_asr8 | alu_ror8 =>
out_alu <= "00000000" & carry_in & left(7 downto 1); -- ror8/asr8/lsr8
when alu_neg =>
out_alu <= right - left; -- neg (right=0)
when alu_com =>
out_alu <= not left;
when alu_clr | alu_ld8 | alu_ld16 | alu_lea =>
out_alu <= right; -- clr, ld
when alu_st8 | alu_st16 | alu_andcc | alu_orcc | alu_tfr =>
out_alu <= left;
when alu_daa =>
out_alu <= left + ("00000000" & daa_reg);
when alu_sex =>
if left(7) = '0' then
out_alu <= "00000000" & left(7 downto 0);
else
out_alu <= "11111111" & left(7 downto 0);
end if;
when others =>
out_alu <= left; -- nop
end case;
 
--
-- carry bit
--
case alu_ctrl is
when alu_add8 | alu_adc =>
cc_out(CBIT) <= (left(7) and right(7)) or
(left(7) and not out_alu(7)) or
(right(7) and not out_alu(7));
when alu_sub8 | alu_sbc =>
cc_out(CBIT) <= ((not left(7)) and right(7)) or
((not left(7)) and out_alu(7)) or
(right(7) and out_alu(7));
when alu_add16 =>
cc_out(CBIT) <= (left(15) and right(15)) or
(left(15) and not out_alu(15)) or
(right(15) and not out_alu(15));
when alu_sub16 =>
cc_out(CBIT) <= ((not left(15)) and right(15)) or
((not left(15)) and out_alu(15)) or
(right(15) and out_alu(15));
when alu_ror8 | alu_lsr16 | alu_lsr8 | alu_asr8 =>
cc_out(CBIT) <= left(0);
when alu_rol8 | alu_asl8 =>
cc_out(CBIT) <= left(7);
when alu_lsl16 =>
cc_out(CBIT) <= left(15);
when alu_com =>
cc_out(CBIT) <= '1';
when alu_neg | alu_clr =>
cc_out(CBIT) <= out_alu(7) or out_alu(6) or out_alu(5) or out_alu(4) or
out_alu(3) or out_alu(2) or out_alu(1) or out_alu(0);
when alu_mul =>
cc_out(CBIT) <= out_alu(7);
when alu_daa =>
if ( daa_reg(7 downto 4) = "0110" ) then
cc_out(CBIT) <= '1';
else
cc_out(CBIT) <= '0';
end if;
when alu_andcc =>
cc_out(CBIT) <= left(CBIT) and cc(CBIT);
when alu_orcc =>
cc_out(CBIT) <= left(CBIT) or cc(CBIT);
when alu_tfr =>
cc_out(CBIT) <= left(CBIT);
when others =>
cc_out(CBIT) <= cc(CBIT);
end case;
--
-- Zero flag
--
case alu_ctrl is
when alu_add8 | alu_sub8 |
alu_adc | alu_sbc |
alu_and | alu_ora | alu_eor |
alu_inc | alu_dec |
alu_neg | alu_com | alu_clr |
alu_rol8 | alu_ror8 | alu_asr8 | alu_asl8 | alu_lsr8 |
alu_ld8 | alu_st8 | alu_sex | alu_daa =>
cc_out(ZBIT) <= not( out_alu(7) or out_alu(6) or out_alu(5) or out_alu(4) or
out_alu(3) or out_alu(2) or out_alu(1) or out_alu(0) );
when alu_add16 | alu_sub16 | alu_mul |
alu_lsl16 | alu_lsr16 |
alu_ld16 | alu_st16 | alu_lea =>
cc_out(ZBIT) <= not( out_alu(15) or out_alu(14) or out_alu(13) or out_alu(12) or
out_alu(11) or out_alu(10) or out_alu(9) or out_alu(8) or
out_alu(7) or out_alu(6) or out_alu(5) or out_alu(4) or
out_alu(3) or out_alu(2) or out_alu(1) or out_alu(0) );
when alu_andcc =>
cc_out(ZBIT) <= left(ZBIT) and cc(ZBIT);
when alu_orcc =>
cc_out(ZBIT) <= left(ZBIT) or cc(ZBIT);
when alu_tfr =>
cc_out(ZBIT) <= left(ZBIT);
when others =>
cc_out(ZBIT) <= cc(ZBIT);
end case;
 
--
-- negative flag
--
case alu_ctrl is
when alu_add8 | alu_sub8 |
alu_adc | alu_sbc |
alu_and | alu_ora | alu_eor |
alu_rol8 | alu_ror8 | alu_asr8 | alu_asl8 | alu_lsr8 |
alu_inc | alu_dec | alu_neg | alu_com | alu_clr |
alu_ld8 | alu_st8 | alu_sex | alu_daa =>
cc_out(NBIT) <= out_alu(7);
when alu_add16 | alu_sub16 |
alu_lsl16 | alu_lsr16 |
alu_ld16 | alu_st16 =>
cc_out(NBIT) <= out_alu(15);
when alu_andcc =>
cc_out(NBIT) <= left(NBIT) and cc(NBIT);
when alu_orcc =>
cc_out(NBIT) <= left(NBIT) or cc(NBIT);
when alu_tfr =>
cc_out(NBIT) <= left(NBIT);
when others =>
cc_out(NBIT) <= cc(NBIT);
end case;
 
--
-- Interrupt mask flag
--
case alu_ctrl is
when alu_andcc =>
cc_out(IBIT) <= left(IBIT) and cc(IBIT);
when alu_orcc =>
cc_out(IBIT) <= left(IBIT) or cc(IBIT);
when alu_tfr =>
cc_out(IBIT) <= left(IBIT);
when alu_seif | alu_sei =>
cc_out(IBIT) <= '1';
when others =>
cc_out(IBIT) <= cc(IBIT); -- interrupt mask
end case;
 
--
-- Half Carry flag
--
case alu_ctrl is
when alu_add8 | alu_adc =>
cc_out(HBIT) <= (left(3) and right(3)) or
(right(3) and not out_alu(3)) or
(left(3) and not out_alu(3));
when alu_andcc =>
cc_out(HBIT) <= left(HBIT) and cc(HBIT);
when alu_orcc =>
cc_out(HBIT) <= left(HBIT) or cc(HBIT);
when alu_tfr =>
cc_out(HBIT) <= left(HBIT);
when others =>
cc_out(HBIT) <= cc(HBIT);
end case;
 
--
-- Overflow flag
--
case alu_ctrl is
when alu_add8 | alu_adc =>
cc_out(VBIT) <= (left(7) and right(7) and (not out_alu(7))) or
((not left(7)) and (not right(7)) and out_alu(7));
when alu_sub8 | alu_sbc =>
cc_out(VBIT) <= (left(7) and (not right(7)) and (not out_alu(7))) or
((not left(7)) and right(7) and out_alu(7));
when alu_add16 =>
cc_out(VBIT) <= (left(15) and right(15) and (not out_alu(15))) or
((not left(15)) and (not right(15)) and out_alu(15));
when alu_sub16 =>
cc_out(VBIT) <= (left(15) and (not right(15)) and (not out_alu(15))) or
((not left(15)) and right(15) and out_alu(15));
when alu_inc =>
cc_out(VBIT) <= ((not left(7)) and left(6) and left(5) and left(4) and
left(3) and left(2) and left(1) and left(0));
when alu_dec | alu_neg =>
cc_out(VBIT) <= (left(7) and (not left(6)) and (not left(5)) and (not left(4)) and
(not left(3)) and (not left(2)) and (not left(1)) and (not left(0)));
-- 6809 Programming reference manual says
-- V not affected by ASR, LSR and ROR
-- This is different to the 6800
-- John Kent 6th June 2006
-- when alu_asr8 =>
-- cc_out(VBIT) <= left(0) xor left(7);
-- when alu_lsr8 | alu_lsr16 =>
-- cc_out(VBIT) <= left(0);
-- when alu_ror8 =>
-- cc_out(VBIT) <= left(0) xor cc(CBIT);
when alu_lsl16 =>
cc_out(VBIT) <= left(15) xor left(14);
when alu_rol8 | alu_asl8 =>
cc_out(VBIT) <= left(7) xor left(6);
--
-- 11th July 2006 - John Kent
-- What DAA does with V is anyones guess
-- It is undefined in the 6809 programming manual
--
when alu_daa =>
cc_out(VBIT) <= left(7) xor out_alu(7) xor cc(CBIT);
-- CLR resets V Bit
-- John Kent 6th June 2006
when alu_and | alu_ora | alu_eor | alu_com | alu_clr |
alu_st8 | alu_st16 | alu_ld8 | alu_ld16 | alu_sex =>
cc_out(VBIT) <= '0';
when alu_andcc =>
cc_out(VBIT) <= left(VBIT) and cc(VBIT);
when alu_orcc =>
cc_out(VBIT) <= left(VBIT) or cc(VBIT);
when alu_tfr =>
cc_out(VBIT) <= left(VBIT);
when others =>
cc_out(VBIT) <= cc(VBIT);
end case;
 
case alu_ctrl is
when alu_andcc =>
cc_out(FBIT) <= left(FBIT) and cc(FBIT);
when alu_orcc =>
cc_out(FBIT) <= left(FBIT) or cc(FBIT);
when alu_tfr =>
cc_out(FBIT) <= left(FBIT);
when alu_seif =>
cc_out(FBIT) <= '1';
when others =>
cc_out(FBIT) <= cc(FBIT);
end case;
 
case alu_ctrl is
when alu_andcc =>
cc_out(EBIT) <= left(EBIT) and cc(EBIT);
when alu_orcc =>
cc_out(EBIT) <= left(EBIT) or cc(EBIT);
when alu_tfr =>
cc_out(EBIT) <= left(EBIT);
when alu_see =>
cc_out(EBIT) <= '1';
when alu_cle =>
cc_out(EBIT) <= '0';
when others =>
cc_out(EBIT) <= cc(EBIT);
end case;
end process;
 
------------------------------------
--
-- state sequencer
--
------------------------------------
process( state, saved_state,
op_code, pre_code,
cc, ea, md, iv, fic, halt,
nmi_req, firq, irq, lic )
variable cond_true : boolean; -- variable used to evaluate coditional branches
begin
cond_true := (1=1);
ba <= '0';
bs <= '0';
lic <= '0';
opfetch <= '0';
iv_ctrl <= latch_iv;
-- Registers preserved
cc_ctrl <= latch_cc;
acca_ctrl <= latch_acca;
accb_ctrl <= latch_accb;
dp_ctrl <= latch_dp;
ix_ctrl <= latch_ix;
iy_ctrl <= latch_iy;
up_ctrl <= latch_up;
sp_ctrl <= latch_sp;
pc_ctrl <= latch_pc;
md_ctrl <= latch_md;
ea_ctrl <= latch_ea;
op_ctrl <= latch_op;
pre_ctrl <= latch_pre;
-- ALU Idle
left_ctrl <= pc_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
-- Bus idle
addr_ctrl <= idle_ad;
dout_ctrl <= cc_dout;
-- Next State Fetch
st_ctrl <= idle_st;
return_state <= fetch_state;
next_state <= fetch_state;
 
case state is
when reset_state => -- released from reset
-- reset the registers
iv_ctrl <= reset_iv;
op_ctrl <= reset_op;
pre_ctrl <= reset_pre;
cc_ctrl <= reset_cc;
acca_ctrl <= reset_acca;
accb_ctrl <= reset_accb;
dp_ctrl <= reset_dp;
ix_ctrl <= reset_ix;
iy_ctrl <= reset_iy;
up_ctrl <= reset_up;
sp_ctrl <= reset_sp;
pc_ctrl <= reset_pc;
ea_ctrl <= reset_ea;
md_ctrl <= reset_md;
st_ctrl <= reset_st;
next_state <= vect_hi_state;
 
--
-- Jump via interrupt vector
-- iv holds interrupt type
-- fetch PC hi from vector location
--
when vect_hi_state =>
-- fetch pc low interrupt vector
pc_ctrl <= pull_hi_pc;
addr_ctrl <= int_hi_ad;
bs <= '1';
next_state <= vect_lo_state;
 
--
-- jump via interrupt vector
-- iv holds vector type
-- fetch PC lo from vector location
--
when vect_lo_state =>
-- fetch the vector low byte
pc_ctrl <= pull_lo_pc;
addr_ctrl <= int_lo_ad;
bs <= '1';
next_state <= fetch_state;
 
when vect_idle_state =>
--
-- Last Instruction Cycle for SWI, SWI2 & SWI3
--
if op_code = "00111111" then
lic <= '1';
end if;
next_state <= fetch_state;
 
--
-- Here to fetch an instruction
-- PC points to opcode
--
when fetch_state =>
-- fetch the op code
opfetch <= '1';
op_ctrl <= fetch_op;
pre_ctrl <= fetch_pre;
ea_ctrl <= reset_ea;
-- Fetch op code
addr_ctrl <= fetch_ad;
-- Advance the PC to fetch next instruction byte
pc_ctrl <= incr_pc;
next_state <= decode1_state;
 
--
-- Here to decode instruction
-- and fetch next byte of intruction
-- whether it be necessary or not
--
when decode1_state =>
-- fetch first byte of address or immediate data
ea_ctrl <= fetch_first_ea;
md_ctrl <= fetch_first_md;
addr_ctrl <= fetch_ad;
case op_code(7 downto 4) is
--
-- direct single op (2 bytes)
-- 6809 => 6 cycles
-- cpu09 => 5 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 ea_hi=dp / ea_lo=(pc) / pc=pc+1
-- 3 md_lo=(ea) / pc=pc
-- 4 alu_left=md / md=alu_out / pc=pc
-- 5 (ea)=md_lo / pc=pc
--
-- Exception is JMP
-- 6809 => 3 cycles
-- cpu09 => 3 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 ea_hi=dp / ea_lo=(pc) / pc=pc+1
-- 3 pc=ea
--
when "0000" =>
-- advance the PC
pc_ctrl <= incr_pc;
 
case op_code(3 downto 0) is
when "1110" => -- jmp
next_state <= jmp_state;
 
when "1111" => -- clr
next_state <= single_op_exec_state;
 
when others =>
next_state <= single_op_read_state;
end case;
 
-- acca / accb inherent instructions
when "0001" =>
case op_code(3 downto 0) is
--
-- Page2 pre byte
-- pre=(pc) / pc=pc+1
-- op=(pc) / pc=pc+1
--
when "0000" => -- page2
opfetch <= '1';
op_ctrl <= fetch_op;
-- advance pc
pc_ctrl <= incr_pc;
next_state <= decode2_state;
 
--
-- Page3 pre byte
-- pre=(pc) / pc=pc+1
-- op=(pc) / pc=pc+1
--
when "0001" => -- page3
opfetch <= '1';
op_ctrl <= fetch_op;
-- advance pc
pc_ctrl <= incr_pc;
next_state <= decode3_state;
 
--
-- nop - No operation ( 1 byte )
-- 6809 => 2 cycles
-- cpu09 => 2 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 decode
--
when "0010" => -- nop
lic <= '1';
next_state <= fetch_state;
 
--
-- sync - halt execution until an interrupt is received
-- interrupt may be NMI, IRQ or FIRQ
-- program execution continues if the
-- interrupt is asserted for 3 clock cycles
-- note that registers are not pushed onto the stack
-- CPU09 => Interrupts need only be asserted for one clock cycle
--
when "0011" => -- sync
next_state <= sync_state;
 
--
-- lbra -- long branch (3 bytes)
-- 6809 => 5 cycles
-- cpu09 => 4 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1
-- 3 md_hi=md_lo / md_lo=(pc) / pc=pc+1
-- 4 pc=pc+md
--
when "0110" =>
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= lbranch_state;
 
--
-- lbsr - long branch to subroutine (3 bytes)
-- 6809 => 9 cycles
-- cpu09 => 6 cycles
-- 1 op=(pc) /pc=pc+1
-- 2 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1 / sp=sp-1
-- 3 md_hi=md_lo / md_lo=(pc) / pc=pc+1
-- 4 (sp)= pc_lo / sp=sp-1 / pc=pc
-- 5 (sp)=pc_hi / pc=pc
-- 6 pc=pc+md
--
when "0111" =>
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= lbranch_state;
 
--
-- Decimal Adjust Accumulator
--
when "1001" => -- daa
left_ctrl <= acca_left;
right_ctrl <= accb_right;
alu_ctrl <= alu_daa;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
lic <= '1';
next_state <= fetch_state;
 
--
-- OR Condition Codes
--
when "1010" => -- orcc
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= orcc_state;
 
--
-- AND Condition Codes
--
when "1100" => -- andcc
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= andcc_state;
 
--
-- Sign Extend
--
when "1101" => -- sex
left_ctrl <= accb_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_sex;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
lic <= '1';
next_state <= fetch_state;
 
--
-- Exchange Registers
--
when "1110" => -- exg
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= exg_state;
 
--
-- Transfer Registers
--
when "1111" => -- tfr
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= tfr_state;
 
when others =>
-- increment the pc
pc_ctrl <= incr_pc;
lic <= '1';
next_state <= fetch_state;
end case;
 
--
-- Short branch conditional
-- 6809 => always 3 cycles
-- cpu09 => always = 3 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1 / test cc
-- 3 if cc tru pc=pc+md else pc=pc
--
when "0010" => -- branch conditional
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= sbranch_state;
 
--
-- Single byte stack operators
-- Do not advance PC
--
when "0011" =>
--
-- lea - load effective address (2+ bytes)
-- 6809 => 4 cycles + addressing mode
-- cpu09 => 4 cycles + addressing mode
-- 1 op=(pc) / pc=pc+1
-- 2 md_lo=(pc) / pc=pc+1
-- 3 calculate ea
-- 4 ix/iy/sp/up = ea
--
case op_code(3 downto 0) is
when "0000" | -- leax
"0001" | -- leay
"0010" | -- leas
"0011" => -- leau
-- advance PC
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
return_state <= lea_state;
next_state <= indexed_state;
 
--
-- pshs - push registers onto sp stack
-- 6809 => 5 cycles + registers
-- cpu09 => 3 cycles + registers
-- 1 op=(pc) / pc=pc+1
-- 2 ea_lo=(pc) / pc=pc+1
-- 3 if ea(7 downto 0) != "00000000" then sp=sp-1
-- 4 if ea(7) = 1 (sp)=pcl, sp=sp-1
-- 5 if ea(7) = 1 (sp)=pch
-- if ea(6 downto 0) != "0000000" then sp=sp-1
-- 6 if ea(6) = 1 (sp)=upl, sp=sp-1
-- 7 if ea(6) = 1 (sp)=uph
-- if ea(5 downto 0) != "000000" then sp=sp-1
-- 8 if ea(5) = 1 (sp)=iyl, sp=sp-1
-- 9 if ea(5) = 1 (sp)=iyh
-- if ea(4 downto 0) != "00000" then sp=sp-1
-- 10 if ea(4) = 1 (sp)=ixl, sp=sp-1
-- 11 if ea(4) = 1 (sp)=ixh
-- if ea(3 downto 0) != "0000" then sp=sp-1
-- 12 if ea(3) = 1 (sp)=dp
-- if ea(2 downto 0) != "000" then sp=sp-1
-- 13 if ea(2) = 1 (sp)=accb
-- if ea(1 downto 0) != "00" then sp=sp-1
-- 14 if ea(1) = 1 (sp)=acca
-- if ea(0 downto 0) != "0" then sp=sp-1
-- 15 if ea(0) = 1 (sp)=cc
--
when "0100" => -- pshs
-- advance PC
pc_ctrl <= incr_pc;
next_state <= pshs_state;
 
--
-- puls - pull registers of sp stack
-- 6809 => 5 cycles + registers
-- cpu09 => 3 cycles + registers
--
when "0101" => -- puls
-- advance PC
pc_ctrl <= incr_pc;
next_state <= puls_state;
 
--
-- pshu - push registers onto up stack
-- 6809 => 5 cycles + registers
-- cpu09 => 3 cycles + registers
--
when "0110" => -- pshu
-- advance PC
pc_ctrl <= incr_pc;
next_state <= pshu_state;
--
-- pulu - pull registers of up stack
-- 6809 => 5 cycles + registers
-- cpu09 => 3 cycles + registers
--
when "0111" => -- pulu
-- advance PC
pc_ctrl <= incr_pc;
next_state <= pulu_state;
 
--
-- rts - return from subroutine
-- 6809 => 5 cycles
-- cpu09 => 4 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 decode op
-- 3 pc_hi = (sp) / sp=sp+1
-- 4 pc_lo = (sp) / sp=sp+1
--
when "1001" =>
next_state <= pull_return_hi_state;
 
--
-- ADD accb to index register
-- *** Note: this is an unsigned addition.
-- does not affect any condition codes
-- 6809 => 3 cycles
-- cpu09 => 2 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 alu_left=ix / alu_right=accb / ix=alu_out / pc=pc
--
when "1010" => -- abx
left_ctrl <= ix_left;
right_ctrl <= accb_right;
alu_ctrl <= alu_abx;
ix_ctrl <= load_ix;
lic <= '1';
next_state <= fetch_state;
 
--
-- Return From Interrupt
--
when "1011" => -- rti
next_state <= rti_cc_state;
 
--
-- CWAI
--
when "1100" => -- cwai #$<cc_mask>
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- increment pc
pc_ctrl <= incr_pc;
next_state <= cwai_state;
 
--
-- MUL Multiply
--
when "1101" => -- mul
-- move acca to md
left_ctrl <= acca_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_st16;
md_ctrl <= load_md; -- over ride md_ctrl <= second byte fetch
next_state <= mulea_state;
--
-- SWI Software Interrupt
--
when "1111" => -- swi
-- predecrement SP
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= swi_iv;
st_ctrl <= push_st;
return_state <= int_swimask_state;
next_state <= int_entire_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
 
end case;
--
-- Accumulator A Single operand
-- source = acca, dest = acca
-- Do not advance PC
-- Typically 2 cycles 1 bytes
-- 1 opcode fetch
-- 2 post byte fetch / instruction decode
-- Note that there is no post byte
-- so do not advance PC in decode cycle
-- Re-run opcode fetch cycle after decode
--
when "0100" => -- acca single op
left_ctrl <= acca_left;
case op_code(3 downto 0) is
when "0000" => -- neg
right_ctrl <= zero_right;
alu_ctrl <= alu_neg;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
when "0011" => -- com
right_ctrl <= zero_right;
alu_ctrl <= alu_com;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "0100" => -- lsr
right_ctrl <= zero_right;
alu_ctrl <= alu_lsr8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "0110" => -- ror
right_ctrl <= zero_right;
alu_ctrl <= alu_ror8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "0111" => -- asr
right_ctrl <= zero_right;
alu_ctrl <= alu_asr8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "1000" => -- asl
right_ctrl <= zero_right;
alu_ctrl <= alu_asl8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "1001" => -- rol
right_ctrl <= zero_right;
alu_ctrl <= alu_rol8;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "1010" => -- dec
right_ctrl <= one_right;
alu_ctrl <= alu_dec;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "1011" => -- undefined
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
acca_ctrl <= latch_acca;
cc_ctrl <= latch_cc;
 
when "1100" => -- inc
right_ctrl <= one_right;
alu_ctrl <= alu_inc;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when "1101" => -- tst
right_ctrl <= zero_right;
alu_ctrl <= alu_st8;
acca_ctrl <= latch_acca;
cc_ctrl <= load_cc;
 
when "1110" => -- jmp (not defined)
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
acca_ctrl <= latch_acca;
cc_ctrl <= latch_cc;
 
when "1111" => -- clr
right_ctrl <= zero_right;
alu_ctrl <= alu_clr;
acca_ctrl <= load_acca;
cc_ctrl <= load_cc;
 
when others =>
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
acca_ctrl <= latch_acca;
cc_ctrl <= latch_cc;
 
end case;
lic <= '1';
next_state <= fetch_state;
 
--
-- Single Operand accb
-- source = accb, dest = accb
-- Typically 2 cycles 1 bytes
-- 1 opcode fetch
-- 2 post byte fetch / instruction decode
-- Note that there is no post byte
-- so do not advance PC in decode cycle
-- Re-run opcode fetch cycle after decode
--
when "0101" =>
left_ctrl <= accb_left;
case op_code(3 downto 0) is
when "0000" => -- neg
right_ctrl <= zero_right;
alu_ctrl <= alu_neg;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "0011" => -- com
right_ctrl <= zero_right;
alu_ctrl <= alu_com;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "0100" => -- lsr
right_ctrl <= zero_right;
alu_ctrl <= alu_lsr8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "0110" => -- ror
right_ctrl <= zero_right;
alu_ctrl <= alu_ror8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "0111" => -- asr
right_ctrl <= zero_right;
alu_ctrl <= alu_asr8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "1000" => -- asl
right_ctrl <= zero_right;
alu_ctrl <= alu_asl8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "1001" => -- rol
right_ctrl <= zero_right;
alu_ctrl <= alu_rol8;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "1010" => -- dec
right_ctrl <= one_right;
alu_ctrl <= alu_dec;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "1011" => -- undefined
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
accb_ctrl <= latch_accb;
cc_ctrl <= latch_cc;
 
when "1100" => -- inc
right_ctrl <= one_right;
alu_ctrl <= alu_inc;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when "1101" => -- tst
right_ctrl <= zero_right;
alu_ctrl <= alu_st8;
accb_ctrl <= latch_accb;
cc_ctrl <= load_cc;
 
when "1110" => -- jmp (undefined)
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
accb_ctrl <= latch_accb;
cc_ctrl <= latch_cc;
 
when "1111" => -- clr
right_ctrl <= zero_right;
alu_ctrl <= alu_clr;
accb_ctrl <= load_accb;
cc_ctrl <= load_cc;
 
when others =>
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
accb_ctrl <= latch_accb;
cc_ctrl <= latch_cc;
end case;
lic <= '1';
next_state <= fetch_state;
 
--
-- Single operand indexed
-- Two byte instruction so advance PC
-- EA should hold index offset
--
when "0110" => -- indexed single op
-- increment the pc
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
case op_code(3 downto 0) is
when "1110" => -- jmp
return_state <= jmp_state;
 
when "1111" => -- clr
return_state <= single_op_exec_state;
 
when others =>
return_state <= single_op_read_state;
 
end case;
next_state <= indexed_state;
 
--
-- Single operand extended addressing
-- three byte instruction so advance the PC
-- Low order EA holds high order address
--
when "0111" => -- extended single op
-- increment PC
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
 
case op_code(3 downto 0) is
when "1110" => -- jmp
return_state <= jmp_state;
when "1111" => -- clr
return_state <= single_op_exec_state;
when others =>
return_state <= single_op_read_state;
end case;
next_state <= extended_state;
 
when "1000" => -- acca immediate
-- increment the pc
pc_ctrl <= incr_pc;
 
case op_code(3 downto 0) is
when "0011" | -- subd #
"1100" | -- cmpx #
"1110" => -- ldx #
next_state <= imm16_state;
 
--
-- bsr offset - Branch to subroutine (2 bytes)
-- 6809 => 7 cycles
-- cpu09 => 5 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 md_hi=sign(pc) / md_lo=(pc) / sp=sp-1 / pc=pc+1
-- 3 (sp)=pc_lo / sp=sp-1
-- 4 (sp)=pc_hi
-- 5 pc=pc+md
--
when "1101" => -- bsr
-- pre decrement SP
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
--
st_ctrl <= push_st;
return_state <= sbranch_state;
next_state <= push_return_lo_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
 
end case;
 
when "1001" => -- acca direct
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- subd
"1100" | -- cmpx
"1110" => -- ldx
next_state <= dual_op_read16_state;
 
when "0111" => -- sta direct
next_state <= dual_op_write8_state;
 
--
-- jsr direct - Jump to subroutine in direct page (2 bytes)
-- 6809 => 7 cycles
-- cpu09 => 5 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 ea_hi=0 / ea_lo=(pc) / sp=sp-1 / pc=pc+1
-- 3 (sp)=pc_lo / sp=sp-1
-- 4 (sp)=pc_hi
-- 5 pc=ea
--
when "1101" => -- jsr direct
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
--
st_ctrl <= push_st;
return_state <= jmp_state;
next_state <= push_return_lo_state;
 
 
when "1111" => -- stx direct
-- idle ALU
left_ctrl <= ix_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_nop;
cc_ctrl <= latch_cc;
sp_ctrl <= latch_sp;
next_state <= dual_op_write16_state;
 
when others =>
next_state <= dual_op_read8_state;
 
end case;
 
when "1010" => -- acca indexed
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- subd
"1100" | -- cmpx
"1110" => -- ldx
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= indexed_state;
 
when "0111" => -- staa ,x
st_ctrl <= push_st;
return_state <= dual_op_write8_state;
next_state <= indexed_state;
 
when "1101" => -- jsr ,x
-- DO NOT pre decrement SP
st_ctrl <= push_st;
return_state <= jsr_state;
next_state <= indexed_state;
 
when "1111" => -- stx ,x
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= indexed_state;
 
when others =>
st_ctrl <= push_st;
return_state <= dual_op_read8_state;
next_state <= indexed_state;
end case;
 
when "1011" => -- acca extended
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- subd
"1100" | -- cmpx
"1110" => -- ldx
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= extended_state;
 
when "0111" => -- staa >
st_ctrl <= push_st;
return_state <= dual_op_write8_state;
next_state <= extended_state;
 
when "1101" => -- jsr >extended
-- DO NOT pre decrement sp
st_ctrl <= push_st;
return_state <= jsr_state;
next_state <= extended_state;
 
when "1111" => -- stx >
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= extended_state;
 
when others =>
st_ctrl <= push_st;
return_state <= dual_op_read8_state;
next_state <= extended_state;
 
end case;
 
when "1100" => -- accb immediate
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- addd #
"1100" | -- ldd #
"1110" => -- ldu #
next_state <= imm16_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
 
end case;
 
when "1101" => -- accb direct
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- addd
"1100" | -- ldd
"1110" => -- ldu
next_state <= dual_op_read16_state;
 
when "0111" => -- stab direct
next_state <= dual_op_write8_state;
 
when "1101" => -- std direct
next_state <= dual_op_write16_state;
 
when "1111" => -- stu direct
next_state <= dual_op_write16_state;
 
when others =>
next_state <= dual_op_read8_state;
 
end case;
 
when "1110" => -- accb indexed
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- addd
"1100" | -- ldd
"1110" => -- ldu
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= indexed_state;
 
when "0111" => -- stab indexed
st_ctrl <= push_st;
return_state <= dual_op_write8_state;
next_state <= indexed_state;
 
when "1101" => -- std indexed
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= indexed_state;
 
when "1111" => -- stu indexed
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= indexed_state;
 
when others =>
st_ctrl <= push_st;
return_state <= dual_op_read8_state;
next_state <= indexed_state;
end case;
 
when "1111" => -- accb extended
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- addd
"1100" | -- ldd
"1110" => -- ldu
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= extended_state;
 
when "0111" => -- stab extended
st_ctrl <= push_st;
return_state <= dual_op_write8_state;
next_state <= extended_state;
 
when "1101" => -- std extended
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= extended_state;
 
when "1111" => -- stu extended
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= extended_state;
 
when others =>
st_ctrl <= push_st;
return_state <= dual_op_read8_state;
next_state <= extended_state;
end case;
--
-- not sure why I need this
--
when others =>
lic <= '1';
next_state <= fetch_state;
end case;
 
--
-- Here to decode prefix 2 instruction
-- and fetch next byte of intruction
-- whether it be necessary or not
--
when decode2_state =>
-- fetch first byte of address or immediate data
ea_ctrl <= fetch_first_ea;
md_ctrl <= fetch_first_md;
addr_ctrl <= fetch_ad;
case op_code(7 downto 4) is
--
-- lbcc -- long branch conditional
-- 6809 => branch 6 cycles, no branch 5 cycles
-- cpu09 => always 5 cycles
-- 1 pre=(pc) / pc=pc+1
-- 2 op=(pc) / pc=pc+1
-- 3 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1
-- 4 md_hi=md_lo / md_lo=(pc) / pc=pc+1
-- 5 if cond pc=pc+md else pc=pc
--
when "0010" =>
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= lbranch_state;
 
--
-- Single byte stack operators
-- Do not advance PC
--
when "0011" =>
case op_code(3 downto 0) is
when "1111" => -- swi 2
-- predecrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= swi2_iv;
st_ctrl <= push_st;
return_state <= vect_hi_state;
next_state <= int_entire_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
end case;
 
when "1000" => -- acca immediate
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- cmpd #
"1100" | -- cmpy #
"1110" => -- ldy #
next_state <= imm16_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
 
end case;
 
when "1001" => -- acca direct
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- cmpd <
"1100" | -- cmpy <
"1110" => -- ldy <
next_state <= dual_op_read16_state;
 
when "1111" => -- sty <
next_state <= dual_op_write16_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
 
end case;
 
when "1010" => -- acca indexed
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- cmpd ,ind
"1100" | -- cmpy ,ind
"1110" => -- ldy ,ind
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= indexed_state;
 
when "1111" => -- sty ,ind
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= indexed_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
end case;
 
when "1011" => -- acca extended
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- cmpd <
"1100" | -- cmpy <
"1110" => -- ldy <
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= extended_state;
 
when "1111" => -- sty >
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= extended_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
 
end case;
 
when "1100" => -- accb immediate
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- undef #
"1100" | -- undef #
"1110" => -- lds #
next_state <= imm16_state;
 
when others =>
next_state <= fetch_state;
 
end case;
 
when "1101" => -- accb direct
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- undef <
"1100" | -- undef <
"1110" => -- lds <
next_state <= dual_op_read16_state;
 
when "1111" => -- sts <
next_state <= dual_op_write16_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
 
end case;
 
when "1110" => -- accb indexed
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- undef ,ind
"1100" | -- undef ,ind
"1110" => -- lds ,ind
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= indexed_state;
 
when "1111" => -- sts ,ind
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= indexed_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
 
end case;
 
when "1111" => -- accb extended
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- undef >
"1100" | -- undef >
"1110" => -- lds >
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= extended_state;
 
when "1111" => -- sts >
st_ctrl <= push_st;
return_state <= dual_op_write16_state;
next_state <= extended_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
end case;
 
when others =>
lic <= '1';
next_state <= fetch_state;
end case;
--
-- Here to decode instruction
-- and fetch next byte of intruction
-- whether it be necessary or not
--
when decode3_state =>
ea_ctrl <= fetch_first_ea;
md_ctrl <= fetch_first_md;
addr_ctrl <= fetch_ad;
dout_ctrl <= md_lo_dout;
case op_code(7 downto 4) is
--
-- Single byte stack operators
-- Do not advance PC
--
when "0011" =>
case op_code(3 downto 0) is
when "1111" => -- swi3
-- predecrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= swi3_iv;
st_ctrl <= push_st;
return_state <= vect_hi_state;
next_state <= int_entire_state;
when others =>
lic <= '1';
next_state <= fetch_state;
end case;
 
when "1000" => -- acca immediate
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- cmpu #
"1100" | -- cmps #
"1110" => -- undef #
next_state <= imm16_state;
when others =>
lic <= '1';
next_state <= fetch_state;
end case;
 
when "1001" => -- acca direct
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- cmpu <
"1100" | -- cmps <
"1110" => -- undef <
next_state <= dual_op_read16_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
 
end case;
 
when "1010" => -- acca indexed
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- cmpu ,X
"1100" | -- cmps ,X
"1110" => -- undef ,X
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= indexed_state;
 
when others =>
lic <= '1';
next_state <= fetch_state;
 
end case;
 
when "1011" => -- acca extended
-- increment the pc
pc_ctrl <= incr_pc;
case op_code(3 downto 0) is
when "0011" | -- cmpu >
"1100" | -- cmps >
"1110" => -- undef >
st_ctrl <= push_st;
return_state <= dual_op_read16_state;
next_state <= extended_state;
when others =>
lic <= '1';
next_state <= fetch_state;
end case;
 
when others =>
lic <= '1';
next_state <= fetch_state;
end case;
 
--
-- here if ea holds low byte
-- Direct
-- Extended
-- Indexed
-- read memory location
--
when single_op_read_state =>
-- read memory into md
md_ctrl <= fetch_first_md;
addr_ctrl <= read_ad;
dout_ctrl <= md_lo_dout;
next_state <= single_op_exec_state;
 
when single_op_exec_state =>
case op_code(3 downto 0) is
when "0000" => -- neg
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_neg;
cc_ctrl <= load_cc;
md_ctrl <= load_md;
next_state <= single_op_write_state;
when "0011" => -- com
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_com;
cc_ctrl <= load_cc;
md_ctrl <= load_md;
next_state <= single_op_write_state;
when "0100" => -- lsr
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_lsr8;
cc_ctrl <= load_cc;
md_ctrl <= load_md;
next_state <= single_op_write_state;
when "0110" => -- ror
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_ror8;
cc_ctrl <= load_cc;
md_ctrl <= load_md;
next_state <= single_op_write_state;
when "0111" => -- asr
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_asr8;
cc_ctrl <= load_cc;
md_ctrl <= load_md;
next_state <= single_op_write_state;
when "1000" => -- asl
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_asl8;
cc_ctrl <= load_cc;
md_ctrl <= load_md;
next_state <= single_op_write_state;
when "1001" => -- rol
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_rol8;
cc_ctrl <= load_cc;
md_ctrl <= load_md;
next_state <= single_op_write_state;
when "1010" => -- dec
left_ctrl <= md_left;
right_ctrl <= one_right;
alu_ctrl <= alu_dec;
cc_ctrl <= load_cc;
md_ctrl <= load_md;
next_state <= single_op_write_state;
when "1011" => -- undefined
lic <= '1';
next_state <= fetch_state;
when "1100" => -- inc
left_ctrl <= md_left;
right_ctrl <= one_right;
alu_ctrl <= alu_inc;
cc_ctrl <= load_cc;
md_ctrl <= load_md;
next_state <= single_op_write_state;
when "1101" => -- tst
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_st8;
cc_ctrl <= load_cc;
lic <= '1';
next_state <= fetch_state;
when "1110" => -- jmp
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_ld16;
pc_ctrl <= load_pc;
lic <= '1';
next_state <= fetch_state;
when "1111" => -- clr
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_clr;
cc_ctrl <= load_cc;
md_ctrl <= load_md;
next_state <= single_op_write_state;
when others =>
lic <= '1';
next_state <= fetch_state;
end case;
--
-- single operand 8 bit write
-- Write low 8 bits of ALU output
-- EA holds address
-- MD holds data
--
when single_op_write_state =>
-- write ALU low byte output
addr_ctrl <= write_ad;
dout_ctrl <= md_lo_dout;
lic <= '1';
next_state <= fetch_state;
 
--
-- here if ea holds address of low byte
-- read memory location
--
when dual_op_read8_state =>
-- read first data byte from ea
md_ctrl <= fetch_first_md;
addr_ctrl <= read_ad;
lic <= '1';
next_state <= fetch_state;
 
--
-- Here to read a 16 bit value into MD
-- pointed to by the EA register
-- The first byte is read
-- and the EA is incremented
--
when dual_op_read16_state =>
-- increment the effective address
left_ctrl <= ea_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
-- read the high byte of the 16 bit data
md_ctrl <= fetch_first_md;
addr_ctrl <= read_ad;
next_state <= dual_op_read16_2_state;
 
--
-- here to read the second byte
-- pointed to by EA into MD
--
when dual_op_read16_2_state =>
-- read the low byte of the 16 bit data
md_ctrl <= fetch_next_md;
addr_ctrl <= read_ad;
lic <= '1';
next_state <= fetch_state;
 
--
-- 16 bit Write state
-- EA hold address of memory to write to
-- Advance the effective address in ALU
-- decode op_code to determine which
-- register to write
--
when dual_op_write16_state =>
-- increment the effective address
left_ctrl <= ea_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
-- write the ALU hi byte at ea
addr_ctrl <= write_ad;
if op_code(6) = '0' then
case op_code(3 downto 0) is
when "1111" => -- stx / sty
case pre_code is
when "00010000" => -- page 2 -- sty
dout_ctrl <= iy_hi_dout;
when others => -- page 1 -- stx
dout_ctrl <= ix_hi_dout;
end case;
when others =>
dout_ctrl <= md_hi_dout;
end case;
else
case op_code(3 downto 0) is
when "1101" => -- std
dout_ctrl <= acca_dout; -- acca is high byte of ACCD
when "1111" => -- stu / sts
case pre_code is
when "00010000" => -- page 2 -- sts
dout_ctrl <= sp_hi_dout;
when others => -- page 1 -- stu
dout_ctrl <= up_hi_dout;
end case;
when others =>
dout_ctrl <= md_hi_dout;
end case;
end if;
next_state <= dual_op_write8_state;
 
--
-- Dual operand 8 bit write
-- Write 8 bit accumulator
-- or low byte of 16 bit register
-- EA holds address
-- decode opcode to determine
-- which register to apply to the bus
-- Also set the condition codes here
--
when dual_op_write8_state =>
if op_code(6) = '0' then
case op_code(3 downto 0) is
when "0111" => -- sta
dout_ctrl <= acca_dout;
when "1111" => -- stx / sty
case pre_code is
when "00010000" => -- page 2 -- sty
dout_ctrl <= iy_lo_dout;
when others => -- page 1 -- stx
dout_ctrl <= ix_lo_dout;
end case;
when others =>
dout_ctrl <= md_lo_dout;
end case;
else
case op_code(3 downto 0) is
when "0111" => -- stb
dout_ctrl <= accb_dout;
when "1101" => -- std
dout_ctrl <= accb_dout; -- accb is low byte of accd
when "1111" => -- stu / sts
case pre_code is
when "00010000" => -- page 2 -- sts
dout_ctrl <= sp_lo_dout;
when others => -- page 1 -- stu
dout_ctrl <= up_lo_dout;
end case;
when others =>
dout_ctrl <= md_lo_dout;
end case;
end if;
-- write ALU low byte output
addr_ctrl <= write_ad;
lic <= '1';
next_state <= fetch_state;
 
--
-- 16 bit immediate addressing mode
--
when imm16_state =>
-- increment pc
pc_ctrl <= incr_pc;
-- fetch next immediate byte
md_ctrl <= fetch_next_md;
addr_ctrl <= fetch_ad;
lic <= '1';
next_state <= fetch_state;
 
--
-- md & ea holds 8 bit index offset
-- calculate the effective memory address
-- using the alu
--
when indexed_state =>
--
-- decode indexing mode
--
if md(7) = '0' then
case md(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
when "01" =>
left_ctrl <= iy_left;
when "10" =>
left_ctrl <= up_left;
when others =>
-- when "11" =>
left_ctrl <= sp_left;
end case;
right_ctrl <= md_sign5_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
next_state <= saved_state;
 
else
case md(3 downto 0) is
when "0000" => -- ,R+
case md(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
when "01" =>
left_ctrl <= iy_left;
when "10" =>
left_ctrl <= up_left;
when others =>
left_ctrl <= sp_left;
end case;
--
right_ctrl <= zero_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
next_state <= postincr1_state;
 
when "0001" => -- ,R++
case md(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
when "01" =>
left_ctrl <= iy_left;
when "10" =>
left_ctrl <= up_left;
when others =>
-- when "11" =>
left_ctrl <= sp_left;
end case;
right_ctrl <= zero_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
next_state <= postincr2_state;
 
when "0010" => -- ,-R
case md(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
ix_ctrl <= load_ix;
when "01" =>
left_ctrl <= iy_left;
iy_ctrl <= load_iy;
when "10" =>
left_ctrl <= up_left;
up_ctrl <= load_up;
when others =>
-- when "11" =>
left_ctrl <= sp_left;
sp_ctrl <= load_sp;
end case;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
ea_ctrl <= load_ea;
next_state <= saved_state;
 
when "0011" => -- ,--R
case md(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
ix_ctrl <= load_ix;
when "01" =>
left_ctrl <= iy_left;
iy_ctrl <= load_iy;
when "10" =>
left_ctrl <= up_left;
up_ctrl <= load_up;
when others =>
-- when "11" =>
left_ctrl <= sp_left;
sp_ctrl <= load_sp;
end case;
right_ctrl <= two_right;
alu_ctrl <= alu_sub16;
ea_ctrl <= load_ea;
if md(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
 
when "0100" => -- ,R (zero offset)
case md(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
when "01" =>
left_ctrl <= iy_left;
when "10" =>
left_ctrl <= up_left;
when others =>
-- when "11" =>
left_ctrl <= sp_left;
end case;
right_ctrl <= zero_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
if md(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
 
when "0101" => -- ACCB,R
case md(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
when "01" =>
left_ctrl <= iy_left;
when "10" =>
left_ctrl <= up_left;
when others =>
-- when "11" =>
left_ctrl <= sp_left;
end case;
right_ctrl <= accb_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
if md(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
 
when "0110" => -- ACCA,R
case md(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
when "01" =>
left_ctrl <= iy_left;
when "10" =>
left_ctrl <= up_left;
when others =>
-- when "11" =>
left_ctrl <= sp_left;
end case;
right_ctrl <= acca_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
if md(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
 
when "0111" => -- undefined
case md(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
when "01" =>
left_ctrl <= iy_left;
when "10" =>
left_ctrl <= up_left;
when others =>
-- when "11" =>
left_ctrl <= sp_left;
end case;
right_ctrl <= zero_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
if md(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
 
when "1000" => -- offset8,R
md_ctrl <= fetch_first_md; -- pick up 8 bit offset
addr_ctrl <= fetch_ad;
pc_ctrl <= incr_pc;
next_state <= index8_state;
 
when "1001" => -- offset16,R
md_ctrl <= fetch_first_md; -- pick up first byte of 16 bit offset
addr_ctrl <= fetch_ad;
pc_ctrl <= incr_pc;
next_state <= index16_state;
 
when "1010" => -- undefined
case md(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
when "01" =>
left_ctrl <= iy_left;
when "10" =>
left_ctrl <= up_left;
when others =>
-- when "11" =>
left_ctrl <= sp_left;
end case;
right_ctrl <= zero_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
--
if md(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
 
when "1011" => -- ACCD,R
case md(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
when "01" =>
left_ctrl <= iy_left;
when "10" =>
left_ctrl <= up_left;
when others =>
-- when "11" =>
left_ctrl <= sp_left;
end case;
right_ctrl <= accd_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
if md(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
 
when "1100" => -- offset8,PC
-- fetch 8 bit offset
md_ctrl <= fetch_first_md;
addr_ctrl <= fetch_ad;
pc_ctrl <= incr_pc;
next_state <= pcrel8_state;
 
when "1101" => -- offset16,PC
-- fetch offset
md_ctrl <= fetch_first_md;
addr_ctrl <= fetch_ad;
pc_ctrl <= incr_pc;
next_state <= pcrel16_state;
 
when "1110" => -- undefined
case md(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
when "01" =>
left_ctrl <= iy_left;
when "10" =>
left_ctrl <= up_left;
when others =>
-- when "11" =>
left_ctrl <= sp_left;
end case;
right_ctrl <= zero_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
if md(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
 
when others =>
-- when "1111" => -- [,address]
-- advance PC to pick up address
md_ctrl <= fetch_first_md;
addr_ctrl <= fetch_ad;
pc_ctrl <= incr_pc;
next_state <= indexaddr_state;
end case;
end if;
 
-- load index register with ea plus one
when postincr1_state =>
left_ctrl <= ea_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
case md(6 downto 5) is
when "00" =>
ix_ctrl <= load_ix;
when "01" =>
iy_ctrl <= load_iy;
when "10" =>
up_ctrl <= load_up;
when others =>
-- when "11" =>
sp_ctrl <= load_sp;
end case;
-- return to previous state
if md(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
 
-- load index register with ea plus two
when postincr2_state =>
-- increment register by two (address)
left_ctrl <= ea_left;
right_ctrl <= two_right;
alu_ctrl <= alu_add16;
case md(6 downto 5) is
when "00" =>
ix_ctrl <= load_ix;
when "01" =>
iy_ctrl <= load_iy;
when "10" =>
up_ctrl <= load_up;
when others =>
-- when "11" =>
sp_ctrl <= load_sp;
end case;
-- return to previous state
if md(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
--
-- ea = index register + md (8 bit signed offset)
-- ea holds post byte
--
when index8_state =>
case ea(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
when "01" =>
left_ctrl <= iy_left;
when "10" =>
left_ctrl <= up_left;
when others =>
-- when "11" =>
left_ctrl <= sp_left;
end case;
-- ea = index reg + md
right_ctrl <= md_sign8_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
-- return to previous state
if ea(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
 
-- fetch low byte of 16 bit indexed offset
when index16_state =>
-- advance pc
pc_ctrl <= incr_pc;
-- fetch low byte
md_ctrl <= fetch_next_md;
addr_ctrl <= fetch_ad;
next_state <= index16_2_state;
 
-- ea = index register + md (16 bit offset)
-- ea holds post byte
when index16_2_state =>
case ea(6 downto 5) is
when "00" =>
left_ctrl <= ix_left;
when "01" =>
left_ctrl <= iy_left;
when "10" =>
left_ctrl <= up_left;
when others =>
-- when "11" =>
left_ctrl <= sp_left;
end case;
-- ea = index reg + md
right_ctrl <= md_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
-- return to previous state
if ea(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
--
-- pc relative with 8 bit signed offest
-- md holds signed offset
--
when pcrel8_state =>
-- ea = pc + signed md
left_ctrl <= pc_left;
right_ctrl <= md_sign8_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
-- return to previous state
if ea(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
 
-- pc relative addressing with 16 bit offset
-- pick up the low byte of the offset in md
-- advance the pc
when pcrel16_state =>
-- advance pc
pc_ctrl <= incr_pc;
-- fetch low byte
md_ctrl <= fetch_next_md;
addr_ctrl <= fetch_ad;
next_state <= pcrel16_2_state;
 
-- pc relative with16 bit signed offest
-- md holds signed offset
when pcrel16_2_state =>
-- ea = pc + md
left_ctrl <= pc_left;
right_ctrl <= md_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
-- return to previous state
if ea(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
 
-- indexed to address
-- pick up the low byte of the address
-- advance the pc
when indexaddr_state =>
-- advance pc
pc_ctrl <= incr_pc;
-- fetch low byte
md_ctrl <= fetch_next_md;
addr_ctrl <= fetch_ad;
next_state <= indexaddr2_state;
 
-- indexed to absolute address
-- md holds address
-- ea hold indexing mode byte
when indexaddr2_state =>
-- ea = md
left_ctrl <= pc_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
ea_ctrl <= load_ea;
-- return to previous state
if ea(4) = '0' then
next_state <= saved_state;
else
next_state <= indirect_state;
end if;
 
--
-- load md with high byte of indirect address
-- pointed to by ea
-- increment ea
--
when indirect_state =>
-- increment ea
left_ctrl <= ea_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
ea_ctrl <= load_ea;
-- fetch high byte
md_ctrl <= fetch_first_md;
addr_ctrl <= read_ad;
next_state <= indirect2_state;
--
-- load md with low byte of indirect address
-- pointed to by ea
-- ea has previously been incremented
--
when indirect2_state =>
-- fetch high byte
md_ctrl <= fetch_next_md;
addr_ctrl <= read_ad;
dout_ctrl <= md_lo_dout;
next_state <= indirect3_state;
--
-- complete idirect addressing
-- by loading ea with md
--
when indirect3_state =>
-- load ea with md
left_ctrl <= ea_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
ea_ctrl <= load_ea;
-- return to previous state
next_state <= saved_state;
 
--
-- ea holds the low byte of the absolute address
-- Move ea low byte into ea high byte
-- load new ea low byte to for absolute 16 bit address
-- advance the program counter
--
when extended_state => -- fetch ea low byte
-- increment pc
pc_ctrl <= incr_pc;
-- fetch next effective address bytes
ea_ctrl <= fetch_next_ea;
addr_ctrl <= fetch_ad;
-- return to previous state
next_state <= saved_state;
 
when lea_state => -- here on load effective address
-- load index register with effective address
left_ctrl <= pc_left;
right_ctrl <= ea_right;
alu_ctrl <= alu_lea;
case op_code(3 downto 0) is
when "0000" => -- leax
cc_ctrl <= load_cc;
ix_ctrl <= load_ix;
when "0001" => -- leay
cc_ctrl <= load_cc;
iy_ctrl <= load_iy;
when "0010" => -- leas
sp_ctrl <= load_sp;
when "0011" => -- leau
up_ctrl <= load_up;
when others =>
null;
end case;
lic <= '1';
next_state <= fetch_state;
 
--
-- jump to subroutine
-- sp=sp-1
-- call push_return_lo_state to save pc
-- return to jmp_state
--
when jsr_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- call push_return_state
st_ctrl <= push_st;
return_state <= jmp_state;
next_state <= push_return_lo_state;
 
--
-- Load pc with ea
-- (JMP)
--
when jmp_state =>
-- load PC with effective address
left_ctrl <= pc_left;
right_ctrl <= ea_right;
alu_ctrl <= alu_ld16;
pc_ctrl <= load_pc;
lic <= '1';
next_state <= fetch_state;
 
--
-- long branch or branch to subroutine
-- pick up next md byte
-- md_hi = md_lo
-- md_lo = (pc)
-- pc=pc+1
-- if a lbsr push return address
-- continue to sbranch_state
-- to evaluate conditional branches
--
when lbranch_state =>
pc_ctrl <= incr_pc;
-- fetch the next byte into md_lo
md_ctrl <= fetch_next_md;
addr_ctrl <= fetch_ad;
-- if lbsr - push return address
-- then continue on to short branch
if op_code = "00010111" then
st_ctrl <= push_st;
return_state <= sbranch_state;
next_state <= push_return_lo_state;
else
next_state <= sbranch_state;
end if;
 
--
-- here to execute conditional branch
-- short conditional branch md = signed 8 bit offset
-- long branch md = 16 bit offset
--
when sbranch_state =>
left_ctrl <= pc_left;
right_ctrl <= md_right;
alu_ctrl <= alu_add16;
-- Test condition for branch
if op_code(7 downto 4) = "0010" then -- conditional branch
case op_code(3 downto 0) is
when "0000" => -- bra
cond_true := (1 = 1);
when "0001" => -- brn
cond_true := (1 = 0);
when "0010" => -- bhi
cond_true := ((cc(CBIT) or cc(ZBIT)) = '0');
when "0011" => -- bls
cond_true := ((cc(CBIT) or cc(ZBIT)) = '1');
when "0100" => -- bcc/bhs
cond_true := (cc(CBIT) = '0');
when "0101" => -- bcs/blo
cond_true := (cc(CBIT) = '1');
when "0110" => -- bne
cond_true := (cc(ZBIT) = '0');
when "0111" => -- beq
cond_true := (cc(ZBIT) = '1');
when "1000" => -- bvc
cond_true := (cc(VBIT) = '0');
when "1001" => -- bvs
cond_true := (cc(VBIT) = '1');
when "1010" => -- bpl
cond_true := (cc(NBIT) = '0');
when "1011" => -- bmi
cond_true := (cc(NBIT) = '1');
when "1100" => -- bge
cond_true := ((cc(NBIT) xor cc(VBIT)) = '0');
when "1101" => -- blt
cond_true := ((cc(NBIT) xor cc(VBIT)) = '1');
when "1110" => -- bgt
cond_true := ((cc(ZBIT) or (cc(NBIT) xor cc(VBIT))) = '0');
when "1111" => -- ble
cond_true := ((cc(ZBIT) or (cc(NBIT) xor cc(VBIT))) = '1');
when others =>
null;
end case;
end if;
if cond_true then
pc_ctrl <= load_pc;
end if;
lic <= '1';
next_state <= fetch_state;
 
--
-- push return address onto the S stack
--
-- (sp) = pc_lo
-- sp = sp - 1
--
when push_return_lo_state =>
-- decrement the sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write PC low
addr_ctrl <= pushs_ad;
dout_ctrl <= pc_lo_dout;
next_state <= push_return_hi_state;
 
--
-- push program counter hi byte onto the stack
-- (sp) = pc_hi
-- sp = sp
-- return to originating state
--
when push_return_hi_state =>
-- write pc hi bytes
addr_ctrl <= pushs_ad;
dout_ctrl <= pc_hi_dout;
next_state <= saved_state;
 
--
-- RTS pull return address from stack
--
when pull_return_hi_state =>
-- increment the sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read pc hi
pc_ctrl <= pull_hi_pc;
addr_ctrl <= pulls_ad;
next_state <= pull_return_lo_state;
 
when pull_return_lo_state =>
-- increment the SP
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read pc low
pc_ctrl <= pull_lo_pc;
addr_ctrl <= pulls_ad;
dout_ctrl <= pc_lo_dout;
--
lic <= '1';
next_state <= fetch_state;
 
when andcc_state =>
-- AND CC with md
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_andcc;
cc_ctrl <= load_cc;
--
lic <= '1';
next_state <= fetch_state;
 
when orcc_state =>
-- OR CC with md
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_orcc;
cc_ctrl <= load_cc;
--
lic <= '1';
next_state <= fetch_state;
 
when tfr_state =>
-- select source register
case md(7 downto 4) is
when "0000" =>
left_ctrl <= accd_left;
when "0001" =>
left_ctrl <= ix_left;
when "0010" =>
left_ctrl <= iy_left;
when "0011" =>
left_ctrl <= up_left;
when "0100" =>
left_ctrl <= sp_left;
when "0101" =>
left_ctrl <= pc_left;
when "1000" =>
left_ctrl <= acca_left;
when "1001" =>
left_ctrl <= accb_left;
when "1010" =>
left_ctrl <= cc_left;
when "1011" =>
left_ctrl <= dp_left;
when others =>
left_ctrl <= md_left;
end case;
right_ctrl <= zero_right;
alu_ctrl <= alu_tfr;
-- select destination register
case md(3 downto 0) is
when "0000" => -- accd
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
when "0001" => -- ix
ix_ctrl <= load_ix;
when "0010" => -- iy
iy_ctrl <= load_iy;
when "0011" => -- up
up_ctrl <= load_up;
when "0100" => -- sp
sp_ctrl <= load_sp;
when "0101" => -- pc
pc_ctrl <= load_pc;
when "1000" => -- acca
acca_ctrl <= load_acca;
when "1001" => -- accb
accb_ctrl <= load_accb;
when "1010" => -- cc
cc_ctrl <= load_cc;
when "1011" => --dp
dp_ctrl <= load_dp;
when others =>
null;
end case;
--
lic <= '1';
next_state <= fetch_state;
 
when exg_state =>
-- save destination register
case md(3 downto 0) is
when "0000" =>
left_ctrl <= accd_left;
when "0001" =>
left_ctrl <= ix_left;
when "0010" =>
left_ctrl <= iy_left;
when "0011" =>
left_ctrl <= up_left;
when "0100" =>
left_ctrl <= sp_left;
when "0101" =>
left_ctrl <= pc_left;
when "1000" =>
left_ctrl <= acca_left;
when "1001" =>
left_ctrl <= accb_left;
when "1010" =>
left_ctrl <= cc_left;
when "1011" =>
left_ctrl <= dp_left;
when others =>
left_ctrl <= md_left;
end case;
right_ctrl <= zero_right;
alu_ctrl <= alu_tfr;
ea_ctrl <= load_ea;
-- call tranfer microcode
next_state <= exg1_state;
 
when exg1_state =>
-- select source register
case md(7 downto 4) is
when "0000" =>
left_ctrl <= accd_left;
when "0001" =>
left_ctrl <= ix_left;
when "0010" =>
left_ctrl <= iy_left;
when "0011" =>
left_ctrl <= up_left;
when "0100" =>
left_ctrl <= sp_left;
when "0101" =>
left_ctrl <= pc_left;
when "1000" =>
left_ctrl <= acca_left;
when "1001" =>
left_ctrl <= accb_left;
when "1010" =>
left_ctrl <= cc_left;
when "1011" =>
left_ctrl <= dp_left;
when others =>
left_ctrl <= md_left;
end case;
right_ctrl <= zero_right;
alu_ctrl <= alu_tfr;
-- select destination register
case md(3 downto 0) is
when "0000" => -- accd
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
when "0001" => -- ix
ix_ctrl <= load_ix;
when "0010" => -- iy
iy_ctrl <= load_iy;
when "0011" => -- up
up_ctrl <= load_up;
when "0100" => -- sp
sp_ctrl <= load_sp;
when "0101" => -- pc
pc_ctrl <= load_pc;
when "1000" => -- acca
acca_ctrl <= load_acca;
when "1001" => -- accb
accb_ctrl <= load_accb;
when "1010" => -- cc
cc_ctrl <= load_cc;
when "1011" => --dp
dp_ctrl <= load_dp;
when others =>
null;
end case;
next_state <= exg2_state;
 
when exg2_state =>
-- restore destination
left_ctrl <= ea_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_tfr;
-- save as source register
case md(7 downto 4) is
when "0000" => -- accd
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
when "0001" => -- ix
ix_ctrl <= load_ix;
when "0010" => -- iy
iy_ctrl <= load_iy;
when "0011" => -- up
up_ctrl <= load_up;
when "0100" => -- sp
sp_ctrl <= load_sp;
when "0101" => -- pc
pc_ctrl <= load_pc;
when "1000" => -- acca
acca_ctrl <= load_acca;
when "1001" => -- accb
accb_ctrl <= load_accb;
when "1010" => -- cc
cc_ctrl <= load_cc;
when "1011" => --dp
dp_ctrl <= load_dp;
when others =>
null;
end case;
lic <= '1';
next_state <= fetch_state;
 
when mulea_state =>
-- move accb to ea
left_ctrl <= accb_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_st16;
ea_ctrl <= load_ea;
next_state <= muld_state;
 
when muld_state =>
-- clear accd
left_ctrl <= acca_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_ld8;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
next_state <= mul0_state;
 
when mul0_state =>
-- if bit 0 of ea set, add accd to md
left_ctrl <= accd_left;
if ea(0) = '1' then
right_ctrl <= md_right;
else
right_ctrl <= zero_right;
end if;
alu_ctrl <= alu_mul;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
md_ctrl <= shiftl_md;
next_state <= mul1_state;
 
when mul1_state =>
-- if bit 1 of ea set, add accd to md
left_ctrl <= accd_left;
if ea(1) = '1' then
right_ctrl <= md_right;
else
right_ctrl <= zero_right;
end if;
alu_ctrl <= alu_mul;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
md_ctrl <= shiftl_md;
next_state <= mul2_state;
 
when mul2_state =>
-- if bit 2 of ea set, add accd to md
left_ctrl <= accd_left;
if ea(2) = '1' then
right_ctrl <= md_right;
else
right_ctrl <= zero_right;
end if;
alu_ctrl <= alu_mul;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
md_ctrl <= shiftl_md;
next_state <= mul3_state;
 
when mul3_state =>
-- if bit 3 of ea set, add accd to md
left_ctrl <= accd_left;
if ea(3) = '1' then
right_ctrl <= md_right;
else
right_ctrl <= zero_right;
end if;
alu_ctrl <= alu_mul;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
md_ctrl <= shiftl_md;
next_state <= mul4_state;
 
when mul4_state =>
-- if bit 4 of ea set, add accd to md
left_ctrl <= accd_left;
if ea(4) = '1' then
right_ctrl <= md_right;
else
right_ctrl <= zero_right;
end if;
alu_ctrl <= alu_mul;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
md_ctrl <= shiftl_md;
next_state <= mul5_state;
 
when mul5_state =>
-- if bit 5 of ea set, add accd to md
left_ctrl <= accd_left;
if ea(5) = '1' then
right_ctrl <= md_right;
else
right_ctrl <= zero_right;
end if;
alu_ctrl <= alu_mul;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
md_ctrl <= shiftl_md;
next_state <= mul6_state;
 
when mul6_state =>
-- if bit 6 of ea set, add accd to md
left_ctrl <= accd_left;
if ea(6) = '1' then
right_ctrl <= md_right;
else
right_ctrl <= zero_right;
end if;
alu_ctrl <= alu_mul;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
md_ctrl <= shiftl_md;
lic <= '1';
next_state <= fetch_state;
 
--
-- Enter here on pushs
-- ea holds post byte
--
when pshs_state =>
-- decrement sp if any registers to be pushed
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
-- idle address
addr_ctrl <= idle_ad;
dout_ctrl <= cc_dout;
if ea(7 downto 0) = "00000000" then
sp_ctrl <= latch_sp;
else
sp_ctrl <= load_sp;
end if;
if ea(7) = '1' then
next_state <= pshs_pcl_state;
elsif ea(6) = '1' then
next_state <= pshs_upl_state;
elsif ea(5) = '1' then
next_state <= pshs_iyl_state;
elsif ea(4) = '1' then
next_state <= pshs_ixl_state;
elsif ea(3) = '1' then
next_state <= pshs_dp_state;
elsif ea(2) = '1' then
next_state <= pshs_accb_state;
elsif ea(1) = '1' then
next_state <= pshs_acca_state;
elsif ea(0) = '1' then
next_state <= pshs_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshs_pcl_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write pc low
addr_ctrl <= pushs_ad;
dout_ctrl <= pc_lo_dout;
next_state <= pshs_pch_state;
 
when pshs_pch_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(6 downto 0) = "0000000" then
sp_ctrl <= latch_sp;
else
sp_ctrl <= load_sp;
end if;
-- write pc hi
addr_ctrl <= pushs_ad;
dout_ctrl <= pc_hi_dout;
if ea(6) = '1' then
next_state <= pshs_upl_state;
elsif ea(5) = '1' then
next_state <= pshs_iyl_state;
elsif ea(4) = '1' then
next_state <= pshs_ixl_state;
elsif ea(3) = '1' then
next_state <= pshs_dp_state;
elsif ea(2) = '1' then
next_state <= pshs_accb_state;
elsif ea(1) = '1' then
next_state <= pshs_acca_state;
elsif ea(0) = '1' then
next_state <= pshs_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
 
when pshs_upl_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write pc low
addr_ctrl <= pushs_ad;
dout_ctrl <= up_lo_dout;
next_state <= pshs_uph_state;
 
when pshs_uph_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(5 downto 0) = "000000" then
sp_ctrl <= latch_sp;
else
sp_ctrl <= load_sp;
end if;
-- write pc hi
addr_ctrl <= pushs_ad;
dout_ctrl <= up_hi_dout;
if ea(5) = '1' then
next_state <= pshs_iyl_state;
elsif ea(4) = '1' then
next_state <= pshs_ixl_state;
elsif ea(3) = '1' then
next_state <= pshs_dp_state;
elsif ea(2) = '1' then
next_state <= pshs_accb_state;
elsif ea(1) = '1' then
next_state <= pshs_acca_state;
elsif ea(0) = '1' then
next_state <= pshs_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshs_iyl_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write iy low
addr_ctrl <= pushs_ad;
dout_ctrl <= iy_lo_dout;
next_state <= pshs_iyh_state;
 
when pshs_iyh_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(4 downto 0) = "00000" then
sp_ctrl <= latch_sp;
else
sp_ctrl <= load_sp;
end if;
-- write iy hi
addr_ctrl <= pushs_ad;
dout_ctrl <= iy_hi_dout;
if ea(4) = '1' then
next_state <= pshs_ixl_state;
elsif ea(3) = '1' then
next_state <= pshs_dp_state;
elsif ea(2) = '1' then
next_state <= pshs_accb_state;
elsif ea(1) = '1' then
next_state <= pshs_acca_state;
elsif ea(0) = '1' then
next_state <= pshs_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshs_ixl_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write ix low
addr_ctrl <= pushs_ad;
dout_ctrl <= ix_lo_dout;
next_state <= pshs_ixh_state;
 
when pshs_ixh_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(3 downto 0) = "0000" then
sp_ctrl <= latch_sp;
else
sp_ctrl <= load_sp;
end if;
-- write ix hi
addr_ctrl <= pushs_ad;
dout_ctrl <= ix_hi_dout;
if ea(3) = '1' then
next_state <= pshs_dp_state;
elsif ea(2) = '1' then
next_state <= pshs_accb_state;
elsif ea(1) = '1' then
next_state <= pshs_acca_state;
elsif ea(0) = '1' then
next_state <= pshs_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshs_dp_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(2 downto 0) = "000" then
sp_ctrl <= latch_sp;
else
sp_ctrl <= load_sp;
end if;
-- write dp
addr_ctrl <= pushs_ad;
dout_ctrl <= dp_dout;
if ea(2) = '1' then
next_state <= pshs_accb_state;
elsif ea(1) = '1' then
next_state <= pshs_acca_state;
elsif ea(0) = '1' then
next_state <= pshs_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshs_accb_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(1 downto 0) = "00" then
sp_ctrl <= latch_sp;
else
sp_ctrl <= load_sp;
end if;
-- write accb
addr_ctrl <= pushs_ad;
dout_ctrl <= accb_dout;
if ea(1) = '1' then
next_state <= pshs_acca_state;
elsif ea(0) = '1' then
next_state <= pshs_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshs_acca_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(0) = '1' then
sp_ctrl <= load_sp;
else
sp_ctrl <= latch_sp;
end if;
-- write acca
addr_ctrl <= pushs_ad;
dout_ctrl <= acca_dout;
if ea(0) = '1' then
next_state <= pshs_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshs_cc_state =>
-- idle sp
-- write cc
addr_ctrl <= pushs_ad;
dout_ctrl <= cc_dout;
lic <= '1';
next_state <= fetch_state;
 
--
-- enter here on PULS
-- ea hold register mask
--
when puls_state =>
if ea(0) = '1' then
next_state <= puls_cc_state;
elsif ea(1) = '1' then
next_state <= puls_acca_state;
elsif ea(2) = '1' then
next_state <= puls_accb_state;
elsif ea(3) = '1' then
next_state <= puls_dp_state;
elsif ea(4) = '1' then
next_state <= puls_ixh_state;
elsif ea(5) = '1' then
next_state <= puls_iyh_state;
elsif ea(6) = '1' then
next_state <= puls_uph_state;
elsif ea(7) = '1' then
next_state <= puls_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when puls_cc_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read cc
cc_ctrl <= pull_cc;
addr_ctrl <= pulls_ad;
if ea(1) = '1' then
next_state <= puls_acca_state;
elsif ea(2) = '1' then
next_state <= puls_accb_state;
elsif ea(3) = '1' then
next_state <= puls_dp_state;
elsif ea(4) = '1' then
next_state <= puls_ixh_state;
elsif ea(5) = '1' then
next_state <= puls_iyh_state;
elsif ea(6) = '1' then
next_state <= puls_uph_state;
elsif ea(7) = '1' then
next_state <= puls_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when puls_acca_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read acca
acca_ctrl <= pull_acca;
addr_ctrl <= pulls_ad;
if ea(2) = '1' then
next_state <= puls_accb_state;
elsif ea(3) = '1' then
next_state <= puls_dp_state;
elsif ea(4) = '1' then
next_state <= puls_ixh_state;
elsif ea(5) = '1' then
next_state <= puls_iyh_state;
elsif ea(6) = '1' then
next_state <= puls_uph_state;
elsif ea(7) = '1' then
next_state <= puls_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when puls_accb_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read accb
accb_ctrl <= pull_accb;
addr_ctrl <= pulls_ad;
if ea(3) = '1' then
next_state <= puls_dp_state;
elsif ea(4) = '1' then
next_state <= puls_ixh_state;
elsif ea(5) = '1' then
next_state <= puls_iyh_state;
elsif ea(6) = '1' then
next_state <= puls_uph_state;
elsif ea(7) = '1' then
next_state <= puls_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when puls_dp_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read dp
dp_ctrl <= pull_dp;
addr_ctrl <= pulls_ad;
if ea(4) = '1' then
next_state <= puls_ixh_state;
elsif ea(5) = '1' then
next_state <= puls_iyh_state;
elsif ea(6) = '1' then
next_state <= puls_uph_state;
elsif ea(7) = '1' then
next_state <= puls_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when puls_ixh_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- pull ix hi
ix_ctrl <= pull_hi_ix;
addr_ctrl <= pulls_ad;
next_state <= puls_ixl_state;
 
when puls_ixl_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read ix low
ix_ctrl <= pull_lo_ix;
addr_ctrl <= pulls_ad;
if ea(5) = '1' then
next_state <= puls_iyh_state;
elsif ea(6) = '1' then
next_state <= puls_uph_state;
elsif ea(7) = '1' then
next_state <= puls_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when puls_iyh_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- pull iy hi
iy_ctrl <= pull_hi_iy;
addr_ctrl <= pulls_ad;
next_state <= puls_iyl_state;
 
when puls_iyl_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read iy low
iy_ctrl <= pull_lo_iy;
addr_ctrl <= pulls_ad;
if ea(6) = '1' then
next_state <= puls_uph_state;
elsif ea(7) = '1' then
next_state <= puls_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when puls_uph_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- pull up hi
up_ctrl <= pull_hi_up;
addr_ctrl <= pulls_ad;
next_state <= puls_upl_state;
 
when puls_upl_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read up low
up_ctrl <= pull_lo_up;
addr_ctrl <= pulls_ad;
if ea(7) = '1' then
next_state <= puls_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when puls_pch_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- pull pc hi
pc_ctrl <= pull_hi_pc;
addr_ctrl <= pulls_ad;
next_state <= puls_pcl_state;
 
when puls_pcl_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read pc low
pc_ctrl <= pull_lo_pc;
addr_ctrl <= pulls_ad;
lic <= '1';
next_state <= fetch_state;
 
--
-- Enter here on pshu
-- ea holds post byte
--
when pshu_state =>
-- decrement up if any registers to be pushed
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(7 downto 0) = "00000000" then
up_ctrl <= latch_up;
else
up_ctrl <= load_up;
end if;
-- write idle bus
if ea(7) = '1' then
next_state <= pshu_pcl_state;
elsif ea(6) = '1' then
next_state <= pshu_spl_state;
elsif ea(5) = '1' then
next_state <= pshu_iyl_state;
elsif ea(4) = '1' then
next_state <= pshu_ixl_state;
elsif ea(3) = '1' then
next_state <= pshu_dp_state;
elsif ea(2) = '1' then
next_state <= pshu_accb_state;
elsif ea(1) = '1' then
next_state <= pshu_acca_state;
elsif ea(0) = '1' then
next_state <= pshu_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
--
-- push PC onto U stack
--
when pshu_pcl_state =>
-- decrement up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
up_ctrl <= load_up;
-- write pc low
addr_ctrl <= pushu_ad;
dout_ctrl <= pc_lo_dout;
next_state <= pshu_pch_state;
 
when pshu_pch_state =>
-- decrement up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(6 downto 0) = "0000000" then
up_ctrl <= latch_up;
else
up_ctrl <= load_up;
end if;
-- write pc hi
addr_ctrl <= pushu_ad;
dout_ctrl <= pc_hi_dout;
if ea(6) = '1' then
next_state <= pshu_spl_state;
elsif ea(5) = '1' then
next_state <= pshu_iyl_state;
elsif ea(4) = '1' then
next_state <= pshu_ixl_state;
elsif ea(3) = '1' then
next_state <= pshu_dp_state;
elsif ea(2) = '1' then
next_state <= pshu_accb_state;
elsif ea(1) = '1' then
next_state <= pshu_acca_state;
elsif ea(0) = '1' then
next_state <= pshu_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshu_spl_state =>
-- decrement up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
up_ctrl <= load_up;
-- write sp low
addr_ctrl <= pushu_ad;
dout_ctrl <= sp_lo_dout;
next_state <= pshu_sph_state;
 
when pshu_sph_state =>
-- decrement up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(5 downto 0) = "000000" then
up_ctrl <= latch_up;
else
up_ctrl <= load_up;
end if;
-- write sp hi
addr_ctrl <= pushu_ad;
dout_ctrl <= sp_hi_dout;
if ea(5) = '1' then
next_state <= pshu_iyl_state;
elsif ea(4) = '1' then
next_state <= pshu_ixl_state;
elsif ea(3) = '1' then
next_state <= pshu_dp_state;
elsif ea(2) = '1' then
next_state <= pshu_accb_state;
elsif ea(1) = '1' then
next_state <= pshu_acca_state;
elsif ea(0) = '1' then
next_state <= pshu_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshu_iyl_state =>
-- decrement up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
up_ctrl <= load_up;
-- write iy low
addr_ctrl <= pushu_ad;
dout_ctrl <= iy_lo_dout;
next_state <= pshu_iyh_state;
 
when pshu_iyh_state =>
-- decrement up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(4 downto 0) = "00000" then
up_ctrl <= latch_up;
else
up_ctrl <= load_up;
end if;
-- write iy hi
addr_ctrl <= pushu_ad;
dout_ctrl <= iy_hi_dout;
if ea(4) = '1' then
next_state <= pshu_ixl_state;
elsif ea(3) = '1' then
next_state <= pshu_dp_state;
elsif ea(2) = '1' then
next_state <= pshu_accb_state;
elsif ea(1) = '1' then
next_state <= pshu_acca_state;
elsif ea(0) = '1' then
next_state <= pshu_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshu_ixl_state =>
-- decrement up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
up_ctrl <= load_up;
-- write ix low
addr_ctrl <= pushu_ad;
dout_ctrl <= ix_lo_dout;
next_state <= pshu_ixh_state;
 
when pshu_ixh_state =>
-- decrement up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(3 downto 0) = "0000" then
up_ctrl <= latch_up;
else
up_ctrl <= load_up;
end if;
-- write ix hi
addr_ctrl <= pushu_ad;
dout_ctrl <= ix_hi_dout;
if ea(3) = '1' then
next_state <= pshu_dp_state;
elsif ea(2) = '1' then
next_state <= pshu_accb_state;
elsif ea(1) = '1' then
next_state <= pshu_acca_state;
elsif ea(0) = '1' then
next_state <= pshu_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshu_dp_state =>
-- decrement up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(2 downto 0) = "000" then
up_ctrl <= latch_up;
else
up_ctrl <= load_up;
end if;
-- write dp
addr_ctrl <= pushu_ad;
dout_ctrl <= dp_dout;
if ea(2) = '1' then
next_state <= pshu_accb_state;
elsif ea(1) = '1' then
next_state <= pshu_acca_state;
elsif ea(0) = '1' then
next_state <= pshu_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshu_accb_state =>
-- decrement up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(1 downto 0) = "00" then
up_ctrl <= latch_up;
else
up_ctrl <= load_up;
end if;
-- write accb
addr_ctrl <= pushu_ad;
dout_ctrl <= accb_dout;
if ea(1) = '1' then
next_state <= pshu_acca_state;
elsif ea(0) = '1' then
next_state <= pshu_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshu_acca_state =>
-- decrement up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
if ea(0) = '0' then
up_ctrl <= latch_up;
else
up_ctrl <= load_up;
end if;
-- write acca
addr_ctrl <= pushu_ad;
dout_ctrl <= acca_dout;
if ea(0) = '1' then
next_state <= pshu_cc_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pshu_cc_state =>
-- idle up
-- write cc
addr_ctrl <= pushu_ad;
dout_ctrl <= cc_dout;
lic <= '1';
next_state <= fetch_state;
 
--
-- enter here on PULU
-- ea hold register mask
--
when pulu_state =>
-- idle UP
-- idle bus
if ea(0) = '1' then
next_state <= pulu_cc_state;
elsif ea(1) = '1' then
next_state <= pulu_acca_state;
elsif ea(2) = '1' then
next_state <= pulu_accb_state;
elsif ea(3) = '1' then
next_state <= pulu_dp_state;
elsif ea(4) = '1' then
next_state <= pulu_ixh_state;
elsif ea(5) = '1' then
next_state <= pulu_iyh_state;
elsif ea(6) = '1' then
next_state <= pulu_sph_state;
elsif ea(7) = '1' then
next_state <= pulu_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pulu_cc_state =>
-- increment up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
up_ctrl <= load_up;
-- read cc
cc_ctrl <= pull_cc;
addr_ctrl <= pullu_ad;
if ea(1) = '1' then
next_state <= pulu_acca_state;
elsif ea(2) = '1' then
next_state <= pulu_accb_state;
elsif ea(3) = '1' then
next_state <= pulu_dp_state;
elsif ea(4) = '1' then
next_state <= pulu_ixh_state;
elsif ea(5) = '1' then
next_state <= pulu_iyh_state;
elsif ea(6) = '1' then
next_state <= pulu_sph_state;
elsif ea(7) = '1' then
next_state <= pulu_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pulu_acca_state =>
-- increment up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
up_ctrl <= load_up;
-- read acca
acca_ctrl <= pull_acca;
addr_ctrl <= pullu_ad;
if ea(2) = '1' then
next_state <= pulu_accb_state;
elsif ea(3) = '1' then
next_state <= pulu_dp_state;
elsif ea(4) = '1' then
next_state <= pulu_ixh_state;
elsif ea(5) = '1' then
next_state <= pulu_iyh_state;
elsif ea(6) = '1' then
next_state <= pulu_sph_state;
elsif ea(7) = '1' then
next_state <= pulu_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pulu_accb_state =>
-- increment up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
up_ctrl <= load_up;
-- read accb
accb_ctrl <= pull_accb;
addr_ctrl <= pullu_ad;
if ea(3) = '1' then
next_state <= pulu_dp_state;
elsif ea(4) = '1' then
next_state <= pulu_ixh_state;
elsif ea(5) = '1' then
next_state <= pulu_iyh_state;
elsif ea(6) = '1' then
next_state <= pulu_sph_state;
elsif ea(7) = '1' then
next_state <= pulu_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pulu_dp_state =>
-- increment up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
up_ctrl <= load_up;
-- read dp
dp_ctrl <= pull_dp;
addr_ctrl <= pullu_ad;
if ea(4) = '1' then
next_state <= pulu_ixh_state;
elsif ea(5) = '1' then
next_state <= pulu_iyh_state;
elsif ea(6) = '1' then
next_state <= pulu_sph_state;
elsif ea(7) = '1' then
next_state <= pulu_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pulu_ixh_state =>
-- increment up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
up_ctrl <= load_up;
-- read ix hi
ix_ctrl <= pull_hi_ix;
addr_ctrl <= pullu_ad;
next_state <= pulu_ixl_state;
 
when pulu_ixl_state =>
-- increment up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
up_ctrl <= load_up;
-- read ix low
ix_ctrl <= pull_lo_ix;
addr_ctrl <= pullu_ad;
if ea(5) = '1' then
next_state <= pulu_iyh_state;
elsif ea(6) = '1' then
next_state <= pulu_sph_state;
elsif ea(7) = '1' then
next_state <= pulu_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pulu_iyh_state =>
-- increment up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
up_ctrl <= load_up;
-- read iy hi
iy_ctrl <= pull_hi_iy;
addr_ctrl <= pullu_ad;
next_state <= pulu_iyl_state;
 
when pulu_iyl_state =>
-- increment up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
up_ctrl <= load_up;
-- read iy low
iy_ctrl <= pull_lo_iy;
addr_ctrl <= pullu_ad;
if ea(6) = '1' then
next_state <= pulu_sph_state;
elsif ea(7) = '1' then
next_state <= pulu_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pulu_sph_state =>
-- increment up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
up_ctrl <= load_up;
-- read sp hi
sp_ctrl <= pull_hi_sp;
addr_ctrl <= pullu_ad;
next_state <= pulu_spl_state;
 
when pulu_spl_state =>
-- increment up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
up_ctrl <= load_up;
-- read sp low
sp_ctrl <= pull_lo_sp;
addr_ctrl <= pullu_ad;
if ea(7) = '1' then
next_state <= pulu_pch_state;
else
lic <= '1';
next_state <= fetch_state;
end if;
 
when pulu_pch_state =>
-- increment up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
up_ctrl <= load_up;
-- pull pc hi
pc_ctrl <= pull_hi_pc;
addr_ctrl <= pullu_ad;
next_state <= pulu_pcl_state;
 
when pulu_pcl_state =>
-- increment up
left_ctrl <= up_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
up_ctrl <= load_up;
-- read pc low
pc_ctrl <= pull_lo_pc;
addr_ctrl <= pullu_ad;
lic <= '1';
next_state <= fetch_state;
 
--
-- pop the Condition codes
--
when rti_cc_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read cc
cc_ctrl <= pull_cc;
addr_ctrl <= pulls_ad;
next_state <= rti_entire_state;
 
--
-- Added RTI cycle 11th July 2006 John Kent.
-- test the "Entire" Flag
-- that has just been popped off the stack
--
when rti_entire_state =>
--
-- The Entire flag must be recovered from the stack
-- before testing.
--
if cc(EBIT) = '1' then
next_state <= rti_acca_state;
else
next_state <= rti_pch_state;
end if;
 
when rti_acca_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read acca
acca_ctrl <= pull_acca;
addr_ctrl <= pulls_ad;
next_state <= rti_accb_state;
 
when rti_accb_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read accb
accb_ctrl <= pull_accb;
addr_ctrl <= pulls_ad;
next_state <= rti_dp_state;
 
when rti_dp_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read dp
dp_ctrl <= pull_dp;
addr_ctrl <= pulls_ad;
next_state <= rti_ixh_state;
 
when rti_ixh_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read ix hi
ix_ctrl <= pull_hi_ix;
addr_ctrl <= pulls_ad;
next_state <= rti_ixl_state;
 
when rti_ixl_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read ix low
ix_ctrl <= pull_lo_ix;
addr_ctrl <= pulls_ad;
next_state <= rti_iyh_state;
 
when rti_iyh_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read iy hi
iy_ctrl <= pull_hi_iy;
addr_ctrl <= pulls_ad;
next_state <= rti_iyl_state;
 
when rti_iyl_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read iy low
iy_ctrl <= pull_lo_iy;
addr_ctrl <= pulls_ad;
next_state <= rti_uph_state;
 
 
when rti_uph_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read up hi
up_ctrl <= pull_hi_up;
addr_ctrl <= pulls_ad;
next_state <= rti_upl_state;
 
when rti_upl_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- read up low
up_ctrl <= pull_lo_up;
addr_ctrl <= pulls_ad;
next_state <= rti_pch_state;
 
when rti_pch_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- pull pc hi
pc_ctrl <= pull_hi_pc;
addr_ctrl <= pulls_ad;
next_state <= rti_pcl_state;
 
when rti_pcl_state =>
-- increment sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_add16;
sp_ctrl <= load_sp;
-- pull pc low
pc_ctrl <= pull_lo_pc;
addr_ctrl <= pulls_ad;
lic <= '1';
next_state <= fetch_state;
 
--
-- here on NMI interrupt
-- Complete execute cycle of the last instruction.
-- If it was a dual operand instruction
--
when int_nmi_state =>
next_state <= int_nmi1_state;
 
-- Idle bus cycle
when int_nmi1_state =>
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= nmi_iv;
st_ctrl <= push_st;
return_state <= int_nmimask_state;
next_state <= int_entire_state;
 
--
-- here on IRQ interrupt
-- Complete execute cycle of the last instruction.
-- If it was a dual operand instruction
--
when int_irq_state =>
next_state <= int_irq1_state;
 
-- pre decrement the sp
-- Idle bus cycle
when int_irq1_state =>
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= irq_iv;
st_ctrl <= push_st;
return_state <= int_irqmask_state;
next_state <= int_entire_state;
 
--
-- here on FIRQ interrupt
-- Complete execution cycle of the last instruction
-- if it was a dual operand instruction
--
when int_firq_state =>
next_state <= int_firq1_state;
 
-- Idle bus cycle
when int_firq1_state =>
-- pre decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
iv_ctrl <= firq_iv;
st_ctrl <= push_st;
return_state <= int_firqmask_state;
next_state <= int_fast_state;
 
--
-- CWAI entry point
-- stack pointer already pre-decremented
-- mask condition codes
--
when cwai_state =>
-- AND CC with md
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_andcc;
cc_ctrl <= load_cc;
st_ctrl <= push_st;
return_state <= int_cwai_state;
next_state <= int_entire_state;
 
--
-- wait here for an interrupt
--
when int_cwai_state =>
if (nmi_req = '1') then
iv_ctrl <= nmi_iv;
next_state <= int_nmimask_state;
--
-- FIRQ & IRQ are level sensitive
--
elsif (firq = '1') and (cc(FBIT) = '0') then
iv_ctrl <= firq_iv;
next_state <= int_firqmask_state;
 
elsif (irq = '1') and (cc(IBIT) = '0') then
iv_ctrl <= irq_iv;
next_state <= int_irqmask_state;
else
next_state <= int_cwai_state;
end if;
--
-- State to mask I Flag and F Flag (NMI)
--
when int_nmimask_state =>
alu_ctrl <= alu_seif;
cc_ctrl <= load_cc;
next_state <= vect_hi_state;
 
--
-- State to mask I Flag and F Flag (FIRQ)
--
when int_firqmask_state =>
alu_ctrl <= alu_seif;
cc_ctrl <= load_cc;
next_state <= vect_hi_state;
 
 
--
-- State to mask I Flag and F Flag (SWI)
--
when int_swimask_state =>
alu_ctrl <= alu_seif;
cc_ctrl <= load_cc;
next_state <= vect_hi_state;
 
--
-- State to mask I Flag only (IRQ)
--
when int_irqmask_state =>
alu_ctrl <= alu_sei;
cc_ctrl <= load_cc;
next_state <= vect_hi_state;
 
--
-- set Entire Flag on SWI, SWI2, SWI3 and CWAI, IRQ and NMI
-- before stacking all registers
--
when int_entire_state =>
-- set entire flag
alu_ctrl <= alu_see;
cc_ctrl <= load_cc;
next_state <= int_pcl_state;
--
-- clear Entire Flag on FIRQ
-- before stacking all registers
--
when int_fast_state =>
-- clear entire flag
alu_ctrl <= alu_cle;
cc_ctrl <= load_cc;
next_state <= int_pcl_state;
 
when int_pcl_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write pc low
addr_ctrl <= pushs_ad;
dout_ctrl <= pc_lo_dout;
next_state <= int_pch_state;
 
when int_pch_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write pc hi
addr_ctrl <= pushs_ad;
dout_ctrl <= pc_hi_dout;
if cc(EBIT) = '1' then
next_state <= int_upl_state;
else
next_state <= int_cc_state;
end if;
 
when int_upl_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write up low
addr_ctrl <= pushs_ad;
dout_ctrl <= up_lo_dout;
next_state <= int_uph_state;
 
when int_uph_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write ix hi
addr_ctrl <= pushs_ad;
dout_ctrl <= up_hi_dout;
next_state <= int_iyl_state;
 
when int_iyl_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write ix low
addr_ctrl <= pushs_ad;
dout_ctrl <= iy_lo_dout;
next_state <= int_iyh_state;
 
when int_iyh_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write ix hi
addr_ctrl <= pushs_ad;
dout_ctrl <= iy_hi_dout;
next_state <= int_ixl_state;
 
when int_ixl_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write ix low
addr_ctrl <= pushs_ad;
dout_ctrl <= ix_lo_dout;
next_state <= int_ixh_state;
 
when int_ixh_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write ix hi
addr_ctrl <= pushs_ad;
dout_ctrl <= ix_hi_dout;
next_state <= int_dp_state;
 
when int_dp_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write accb
addr_ctrl <= pushs_ad;
dout_ctrl <= dp_dout;
next_state <= int_accb_state;
 
when int_accb_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write accb
addr_ctrl <= pushs_ad;
dout_ctrl <= accb_dout;
next_state <= int_acca_state;
 
when int_acca_state =>
-- decrement sp
left_ctrl <= sp_left;
right_ctrl <= one_right;
alu_ctrl <= alu_sub16;
sp_ctrl <= load_sp;
-- write acca
addr_ctrl <= pushs_ad;
dout_ctrl <= acca_dout;
next_state <= int_cc_state;
 
when int_cc_state =>
-- write cc
addr_ctrl <= pushs_ad;
dout_ctrl <= cc_dout;
next_state <= saved_state;
 
--
-- According to the 6809 programming manual:
-- If an interrupt is received and is masked
-- or lasts for less than three cycles, the PC
-- will advance to the next instruction.
-- If an interrupt is unmasked and lasts
-- for more than three cycles, an interrupt
-- will be generated.
-- Note that I don't wait 3 clock cycles.
-- John Kent 11th July 2006
--
when sync_state =>
lic <= '1';
ba <= '1';
--
-- Version 1.28 2015-05-30
-- Exit sync_state on interrupt.
-- If the interrupts are active
-- they will be caught in the state_machine process
-- and the interrupt service routine microcode will be executed.
-- Masked interrupts will exit the sync_state.
-- Moved from the state_machine process to the state_sequencer process
--
if (firq = '1') or (irq = '1') then
next_state <= fetch_state;
else
next_state <= sync_state;
end if;
when halt_state =>
--
-- 2011-10-30 John Kent
-- ba & bs should be high
ba <= '1';
bs <= '1';
if halt = '1' then
next_state <= halt_state;
else
next_state <= fetch_state;
end if;
 
end case;
 
--
-- Ver 1.23 2011-10-30 John Kent
-- First instruction cycle might be
-- fetch_state
-- halt_state
-- int_nmirq_state
-- int_firq_state
--
if fic = '1' then
--
case op_code(7 downto 6) is
--
-- ver 1.29
-- hide last cycle of multiply in fetch
--
when "00" =>
case op_code(5 downto 0) is
when "111101" => -- mul
-- if bit 7 of ea set, add accd to md
left_ctrl <= accd_left;
if ea(7) = '1' then
right_ctrl <= md_right;
else
right_ctrl <= zero_right;
end if;
alu_ctrl <= alu_mul;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
when others =>
null;
end case;
when "10" => -- acca
case op_code(3 downto 0) is
when "0000" => -- suba
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub8;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "0001" => -- cmpa
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub8;
cc_ctrl <= load_cc;
when "0010" => -- sbca
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sbc;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "0011" =>
case pre_code is
when "00010000" => -- page 2 -- cmpd
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
when "00010001" => -- page 3 -- cmpu
left_ctrl <= up_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
when others => -- page 1 -- subd
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
end case;
when "0100" => -- anda
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_and;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "0101" => -- bita
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_and;
cc_ctrl <= load_cc;
when "0110" => -- ldaa
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld8;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "0111" => -- staa
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st8;
cc_ctrl <= load_cc;
when "1000" => -- eora
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_eor;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "1001" => -- adca
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_adc;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "1010" => -- oraa
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ora;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "1011" => -- adda
left_ctrl <= acca_left;
right_ctrl <= md_right;
alu_ctrl <= alu_add8;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
when "1100" =>
case pre_code is
when "00010000" => -- page 2 -- cmpy
left_ctrl <= iy_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
when "00010001" => -- page 3 -- cmps
left_ctrl <= sp_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
when others => -- page 1 -- cmpx
left_ctrl <= ix_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub16;
cc_ctrl <= load_cc;
end case;
when "1101" => -- bsr / jsr
null;
when "1110" => -- ldx
case pre_code is
when "00010000" => -- page 2 -- ldy
left_ctrl <= iy_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
iy_ctrl <= load_iy;
when others => -- page 1 -- ldx
left_ctrl <= ix_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
ix_ctrl <= load_ix;
end case;
when "1111" => -- stx
case pre_code is
when "00010000" => -- page 2 -- sty
left_ctrl <= iy_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
when others => -- page 1 -- stx
left_ctrl <= ix_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
end case;
when others =>
null;
end case;
when "11" => -- accb dual op
case op_code(3 downto 0) is
when "0000" => -- subb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub8;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "0001" => -- cmpb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sub8;
cc_ctrl <= load_cc;
when "0010" => -- sbcb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_sbc;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "0011" => -- addd
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_add16;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
when "0100" => -- andb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_and;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "0101" => -- bitb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_and;
cc_ctrl <= load_cc;
when "0110" => -- ldab
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld8;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "0111" => -- stab
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st8;
cc_ctrl <= load_cc;
when "1000" => -- eorb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_eor;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "1001" => -- adcb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_adc;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "1010" => -- orab
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ora;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "1011" => -- addb
left_ctrl <= accb_left;
right_ctrl <= md_right;
alu_ctrl <= alu_add8;
cc_ctrl <= load_cc;
accb_ctrl <= load_accb;
when "1100" => -- ldd
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
acca_ctrl <= load_hi_acca;
accb_ctrl <= load_accb;
when "1101" => -- std
left_ctrl <= accd_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
when "1110" => -- ldu
case pre_code is
when "00010000" => -- page 2 -- lds
left_ctrl <= sp_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
sp_ctrl <= load_sp;
when others => -- page 1 -- ldu
left_ctrl <= up_left;
right_ctrl <= md_right;
alu_ctrl <= alu_ld16;
cc_ctrl <= load_cc;
up_ctrl <= load_up;
end case;
when "1111" =>
case pre_code is
when "00010000" => -- page 2 -- sts
left_ctrl <= sp_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
when others => -- page 1 -- stu
left_ctrl <= up_left;
right_ctrl <= md_right;
alu_ctrl <= alu_st16;
cc_ctrl <= load_cc;
end case;
when others =>
null;
end case;
when others =>
null;
end case;
 
end if; -- first instruction cycle (fic)
lic_out <= lic;
end process;
 
end rtl;
trunk/rtl/VHDL/cpu09m.vhd Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/rtl/VHDL/cpu09n.vhd =================================================================== --- trunk/rtl/VHDL/cpu09n.vhd (nonexistent) +++ trunk/rtl/VHDL/cpu09n.vhd (revision 130) @@ -0,0 +1,5665 @@ +--===========================================================================-- +-- -- +-- Synthesizable 6809 instruction compatible VHDL CPU core -- +-- -- +--===========================================================================-- +-- +-- File name : cpu09n.vhd +-- +-- Entity name : cpu09 +-- +-- Purpose : 6809 instruction compatible CPU core written in VHDL +-- with Last Instruction Cycle, bus available, bus status, +-- and instruction fetch signals. +-- Not cycle compatible with the original 6809 CPU +-- +-- Dependencies : ieee.std_logic_1164 +-- ieee.std_logic_unsigned +-- +-- Author : John E. Kent +-- +-- Email : dilbert57@opencores.org +-- +-- Web : http://opencores.org/project,system09 +-- +-- Description : VMA (valid memory address) is hight whenever a valid memory +-- access is made by an instruction fetch, interrupt vector fetch +-- or a data read or write otherwise it is low indicating an idle +-- bus cycle. +-- IFETCH (instruction fetch output) is high whenever an +-- instruction byte is read i.e. the program counter is applied +-- to the address bus. +-- LIC (last instruction cycle output) is normally low +-- but goes high on the last cycle of an instruction. +-- BA (bus available output) is normally low but goes high while +-- waiting in a Sync instruction state or the CPU is halted +-- i.e. a DMA grant. +-- BS (bus status output) is normally low but goes high during an +-- interrupt or reset vector fetch or the processor is halted +-- i.e. a DMA grant. +-- +-- Copyright (C) 2003 - 2010 John Kent +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program 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 General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +--===========================================================================-- +-- -- +-- Revision History -- +-- -- +--===========================================================================-- +-- +-- Version 0.1 - 26 June 2003 - John Kent +-- Added extra level in state stack +-- fixed some calls to the extended addressing state +-- +-- Version 0.2 - 5 Sept 2003 - John Kent +-- Fixed 16 bit indexed offset (was doing read rather than fetch) +-- Added/Fixed STY and STS instructions. +-- ORCC_STATE ANDed CC state rather than ORed it - Now fixed +-- CMPX Loaded ACCA and ACCB - Now fixed +-- +-- Version 1.0 - 6 Sep 2003 - John Kent +-- Initial release to Open Cores +-- reversed clock edge +-- +-- Version 1.1 - 29 November 2003 John kent +-- ACCA and ACCB indexed offsets are 2's complement. +-- ALU Right Mux now sign extends ACCA & ACCB offsets +-- Absolute Indirect addressing performed a read on the +-- second byte of the address rather than a fetch +-- so it formed an incorrect address. Now fixed. +-- +-- Version 1.2 - 29 November 2003 John Kent +-- LEAX and LEAY affect the Z bit only +-- LEAS and LEAU do not affect any condition codes +-- added an extra ALU control for LEA. +-- +-- Version 1.3 - 12 December 2003 John Kent +-- CWAI did not work, was missed a PUSH_ST on calling +-- the ANDCC_STATE. Thanks go to Ghassan Kraidy for +-- finding this fault. +-- +-- Version 1.4 - 12 December 2003 John Kent +-- Missing cc_ctrl assignment in otherwise case of +-- lea_state resulted in cc_ctrl being latched in +-- that state. +-- The otherwise statement should never be reached, +-- and has been fixed simply to resolve synthesis warnings. +-- +-- Version 1.5 - 17 january 2004 John kent +-- The clear instruction used "alu_ld8" to control the ALU +-- rather than "alu_clr". This mean the Carry was not being +-- cleared correctly. +-- +-- Version 1.6 - 24 January 2004 John Kent +-- Fixed problems in PSHU instruction +-- +-- Version 1.7 - 25 January 2004 John Kent +-- removed redundant "alu_inx" and "alu_dex' +-- Removed "test_alu" and "test_cc" +-- STD instruction did not set condition codes +-- JMP direct was not decoded properly +-- CLR direct performed an unwanted read cycle +-- Bogus "latch_md" in Page2 indexed addressing +-- +-- Version 1.8 - 27 January 2004 John Kent +-- CWAI in decode1_state should increment the PC. +-- ABX is supposed to be an unsigned addition. +-- Added extra ALU function +-- ASR8 slightly changed in the ALU. +-- +-- Version 1.9 - 20 August 2005 +-- LSR8 is now handled in ASR8 and ROR8 case in the ALU, +-- rather than LSR16. There was a problem with single +-- operand instructions using the MD register which is +-- sign extended on the first 8 bit fetch. +-- +-- Version 1.10 - 13 September 2005 +-- TFR & EXG instructions did not work for the Condition Code Register +-- An extra case has been added to the ALU for the alu_tfr control +-- to assign the left ALU input (alu_left) to the condition code +-- outputs (cc_out). +-- +-- Version 1.11 - 16 September 2005 +-- JSR ,X should not predecrement S before calculating the jump address. +-- The reason is that JSR [0,S] needs S to point to the top of the stack +-- to fetch a valid vector address. The solution is to have the addressing +-- mode microcode called before decrementing S and then decrementing S in +-- JSR_STATE. JSR_STATE in turn calls PUSH_RETURN_LO_STATE rather than +-- PUSH_RETURN_HI_STATE so that both the High & Low halves of the PC are +-- pushed on the stack. This adds one extra bus cycle, but resolves the +-- addressing conflict. I've also removed the pre-decement S in +-- JSR EXTENDED as it also calls JSR_STATE. +-- +-- Version 1.12 - 6th June 2006 +-- 6809 Programming reference manual says V is not affected by ASR, LSR and ROR +-- This is different to the 6800. CLR should reset the V bit. +-- +-- Version 1.13 - 7th July 2006 +-- Disable NMI on reset until S Stack pointer has been loaded. +-- Added nmi_enable signal in sp_reg process and nmi_handler process. +-- +-- Version 1.14 - 11th July 2006 +-- 1. Added new state to RTI called rti_entire_state. +-- This state tests the CC register after it has been loaded +-- from the stack. Previously the current CC was tested which +-- was incorrect. The Entire Flag should be set before the +-- interrupt stacks the CC. +-- 2. On bogus Interrupts, int_cc_state went to rti_state, +-- which was an enumerated state, but not defined anywhere. +-- rti_state has been changed to rti_cc_state so that bogus interrupt +-- will perform an RTI after entering that state. +-- 3. Sync should generate an interrupt if the interrupt masks +-- are cleared. If the interrupt masks are set, then an interrupt +-- will cause the the PC to advance to the next instruction. +-- Note that I don't wait for an interrupt to be asserted for +-- three clock cycles. +-- 4. Added new ALU control state "alu_mul". "alu_mul" is used in +-- the Multiply instruction replacing "alu_add16". This is similar +-- to "alu_add16" except it sets the Carry bit to B7 of the result +-- in ACCB, sets the Zero bit if the 16 bit result is zero, but +-- does not affect The Half carry (H), Negative (N) or Overflow (V) +-- flags. The logic was re-arranged so that it adds md or zero so +-- that the Carry condition code is set on zero multiplicands. +-- 5. DAA (Decimal Adjust Accumulator) should set the Negative (N) +-- and Zero Flags. It will also affect the Overflow (V) flag although +-- the operation is undefined. It's anyones guess what DAA does to V. +-- +-- Version 1.15 - 25th Feb 2007 - John Kent +-- line 9672 changed "if Halt <= '1' then" to "if Halt = '1' then" +-- Changed sensitivity lists. +-- +-- Version 1.16 - 5th February 2008 - John Kent +-- FIRQ interrupts should take priority over IRQ Interrupts. +-- This presumably means they should be tested for before IRQ +-- when they happen concurrently. +-- +-- Version 1.17 - 18th February 2008 - John Kent +-- NMI in CWAI should mask IRQ and FIRQ interrupts +-- +-- Version 1.18 - 21st February 2008 - John Kent +-- Removed default register settings in each case statement +-- and placed them at the beginning of the state sequencer. +-- Modified the SYNC instruction so that the interrupt vector(iv) +-- is not set unless an unmasked FIRQ or IRQ is received. +-- +-- Version 1.19 - 25th February 2008 - John Kent +-- Enumerated separate states for FIRQ/FAST and NMIIRQ/ENTIRE +-- Enumerated separate states for MASKI and MASKIF states +-- Removed code on BSR/JSR in fetch cycle +-- +-- Version 1.20 - 8th October 2011 - John Kent +-- added fetch output which should go high during the fetch cycle +-- +-- Version 1.21 - 8th October 2011 - John Kent +-- added Last Instruction Cycle signal +-- replaced fetch with ifetch (instruction fetch) signal +-- added ba & bs (bus available & bus status) signals +-- +-- Version 1.22 - 2011-10-29 John Kent +-- The halt state isn't correct. +-- The halt state is entered into from the fetch_state +-- It returned to the fetch state which may re-run an execute cycle +-- on the accumulator and it won't necessarily be the last instruction cycle +-- I've changed the halt state to return to the decode1_state +-- +-- Version 1.23 - 2011-10-30 John Kent +-- sample halt in the change_state process if lic is high (last instruction cycle) +-- +-- Version 1.24 - 2011-11-01 John Kent +-- Handle interrupts in change_state process +-- Sample interrupt inputs on last instruction cycle +-- Remove iv_ctrl and implement iv (interrupt vector) in change_state process. +-- Generate fic (first instruction cycle) from lic (last instruction cycle) +-- and use it to complete the dual operand execute cycle before servicing +-- halt or interrupts requests. +-- rename lic to lic_out on the entity declaration so that lic can be tested internally. +-- add int_firq1_state and int_nmirq1_state to allow for the dual operand execute cycle +-- integrated nmi_ctrl into change_state process +-- Reduces the microcode state stack to one entry (saved_state) +-- imm16_state jumps directly to the fetch_state +-- pull_return_lo states jumps directly to the fetch_state +-- duplicate andcc_state as cwai_state +-- rename exg1_state as exg2 state and duplicate tfr_state as exg1_state +-- +-- Version 1.25 - 2011-11-27 John Kent +-- Changed the microcode for saving registers on an interrupt into a microcode subroutine. +-- Removed SWI servicing from the change state process and made SWI, SWI2 & SWI3 +-- call the interrupt microcode subroutine. +-- Added additional states for nmi, and irq for interrupt servicing. +-- Added additional states for nmi/irq, firq, and swi interrupts to mask I & F flags. +-- +-- Version 1.26 - 2013-03-18 John Kent +-- pre-initialized cond_true variable to true in state sequencer +-- re-arranged change_state process slightly +-- +-- Version 1.27 - 2015-05-30 John Kent +-- Added test in state machine for masked IRQ and FIRQ in Sync_state. +-- +-- Version 1.28 - 2015-05-30 John Kent. +-- Moved IRQ and FIRQ test from state machine to the state sequencer Sync_state. +-- +-- Version 1.29 - 2017-02-11 John Kent +-- Make MUL 11 cycles long rather than 13 cycles. +-- 1 fetch_state, 2 decode1_state, +-- 3 mul_state, 4 mulea_state, 5 muld_state +-- 6 mul0_state, 7 mul1_state, 8 mul2_state, 9 mul3_state, +-- 10 mul4_state, 11 mul5_state, 12 mul6_state, 13 mul7_state, +-- move mul_state into decode1_state +-- move mul7_state into fetch_state +-- +-- Version 1.29 - 2017-03-08 John Kent. +-- Moved LIC in ABX ? +-- +-- Version 1.30 -2018-01-13 John Kent +-- cpu09n.vhd +-- replace decode1_state, decode2_state and decode3_state +-- with the one decode_state. +-- $10 $4F = $4F = CLRA on a real MC6809. +-- $10 4F = CLRD on a HD6309 +-- +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity cpu09 is + port ( + clk : in std_logic; -- E clock input (falling edge) + rst : in std_logic; -- reset input (active high) + vma : out std_logic; -- valid memory address (active high) + lic_out : out std_logic; -- last instruction cycle (active high) + ifetch : out std_logic; -- instruction fetch cycle (active high) + opfetch : out std_logic; -- opcode fetch (active high) + ba : out std_logic; -- bus available (high on sync wait or DMA grant) + bs : out std_logic; -- bus status (high on interrupt or reset vector fetch or DMA grant) + addr : out std_logic_vector(15 downto 0); -- address bus output + rw : out std_logic; -- read not write output + data_out : out std_logic_vector(7 downto 0); -- data bus output + data_in : in std_logic_vector(7 downto 0); -- data bus input + irq : in std_logic; -- interrupt request input (active high) + firq : in std_logic; -- fast interrupt request input (active high) + nmi : in std_logic; -- non maskable interrupt request input (active high) + halt : in std_logic; -- halt input (active high) grants DMA + hold : in std_logic -- hold input (active high) extend bus cycle + ); +end cpu09; + +architecture rtl of cpu09 is + + constant EBIT : integer := 7; + constant FBIT : integer := 6; + constant HBIT : integer := 5; + constant IBIT : integer := 4; + constant NBIT : integer := 3; + constant ZBIT : integer := 2; + constant VBIT : integer := 1; + constant CBIT : integer := 0; + + -- + -- Interrupt vector modifiers + -- + constant RST_VEC : std_logic_vector(2 downto 0) := "111"; + constant NMI_VEC : std_logic_vector(2 downto 0) := "110"; + constant SWI_VEC : std_logic_vector(2 downto 0) := "101"; + constant IRQ_VEC : std_logic_vector(2 downto 0) := "100"; + constant FIRQ_VEC : std_logic_vector(2 downto 0) := "011"; + constant SWI2_VEC : std_logic_vector(2 downto 0) := "010"; + constant SWI3_VEC : std_logic_vector(2 downto 0) := "001"; + constant RESV_VEC : std_logic_vector(2 downto 0) := "000"; + + type state_type is (-- Start off in Reset + reset_state, + -- Fetch Interrupt Vectors (including reset) + vect_lo_state, vect_hi_state, vect_idle_state, + -- Fetch Instruction Cycle + fetch_state, + -- Decode Instruction Cycles + decode_state, + -- Calculate Effective Address + imm16_state, + indexed_state, index8_state, index16_state, index16_2_state, + pcrel8_state, pcrel16_state, pcrel16_2_state, + indexaddr_state, indexaddr2_state, + postincr1_state, postincr2_state, + indirect_state, indirect2_state, indirect3_state, + extended_state, + -- single ops + single_op_read_state, + single_op_exec_state, + single_op_write_state, + -- Dual op states + dual_op_read8_state, dual_op_read16_state, dual_op_read16_2_state, + dual_op_write8_state, dual_op_write16_state, + -- + sync_state, halt_state, cwai_state, + -- + andcc_state, orcc_state, + tfr_state, + exg_state, exg1_state, exg2_state, + lea_state, + -- Multiplication + mulea_state, muld_state, + mul0_state, mul1_state, mul2_state, mul3_state, + mul4_state, mul5_state, mul6_state, + -- Branches + lbranch_state, sbranch_state, + -- Jumps, Subroutine Calls and Returns + jsr_state, jmp_state, + push_return_hi_state, push_return_lo_state, + pull_return_hi_state, pull_return_lo_state, + -- Interrupt cycles + int_nmi_state, int_nmi1_state, + int_irq_state, int_irq1_state, + int_firq_state, int_firq1_state, + int_entire_state, int_fast_state, + int_pcl_state, int_pch_state, + int_upl_state, int_uph_state, + int_iyl_state, int_iyh_state, + int_ixl_state, int_ixh_state, + int_dp_state, + int_accb_state, int_acca_state, + int_cc_state, + int_cwai_state, + int_nmimask_state, int_firqmask_state, int_swimask_state, int_irqmask_state, + -- Return From Interrupt + rti_cc_state, rti_entire_state, + rti_acca_state, rti_accb_state, + rti_dp_state, + rti_ixl_state, rti_ixh_state, + rti_iyl_state, rti_iyh_state, + rti_upl_state, rti_uph_state, + rti_pcl_state, rti_pch_state, + -- Push Registers using SP + pshs_state, + pshs_pcl_state, pshs_pch_state, + pshs_upl_state, pshs_uph_state, + pshs_iyl_state, pshs_iyh_state, + pshs_ixl_state, pshs_ixh_state, + pshs_dp_state, + pshs_acca_state, pshs_accb_state, + pshs_cc_state, + -- Pull Registers using SP + puls_state, + puls_cc_state, + puls_acca_state, puls_accb_state, + puls_dp_state, + puls_ixl_state, puls_ixh_state, + puls_iyl_state, puls_iyh_state, + puls_upl_state, puls_uph_state, + puls_pcl_state, puls_pch_state, + -- Push Registers using UP + pshu_state, + pshu_pcl_state, pshu_pch_state, + pshu_spl_state, pshu_sph_state, + pshu_iyl_state, pshu_iyh_state, + pshu_ixl_state, pshu_ixh_state, + pshu_dp_state, + pshu_acca_state, pshu_accb_state, + pshu_cc_state, + -- Pull Registers using UP + pulu_state, + pulu_cc_state, + pulu_acca_state, pulu_accb_state, + pulu_dp_state, + pulu_ixl_state, pulu_ixh_state, + pulu_iyl_state, pulu_iyh_state, + pulu_spl_state, pulu_sph_state, + pulu_pcl_state, pulu_pch_state ); + + type st_type is (reset_st, push_st, idle_st ); + type iv_type is (latch_iv, swi3_iv, swi2_iv, firq_iv, irq_iv, swi_iv, nmi_iv, reset_iv); + type addr_type is (idle_ad, fetch_ad, read_ad, write_ad, pushu_ad, pullu_ad, pushs_ad, pulls_ad, int_hi_ad, int_lo_ad ); + type dout_type is (cc_dout, acca_dout, accb_dout, dp_dout, + ix_lo_dout, ix_hi_dout, iy_lo_dout, iy_hi_dout, + up_lo_dout, up_hi_dout, sp_lo_dout, sp_hi_dout, + pc_lo_dout, pc_hi_dout, md_lo_dout, md_hi_dout ); + type op_type is (reset_op, fetch_op, latch_op ); + type pre_type is (reset_pre, fetch_pre, load_pre, latch_pre ); + type cc_type is (reset_cc, load_cc, pull_cc, latch_cc ); + type acca_type is (reset_acca, load_acca, load_hi_acca, pull_acca, latch_acca ); + type accb_type is (reset_accb, load_accb, pull_accb, latch_accb ); + type dp_type is (reset_dp, load_dp, pull_dp, latch_dp ); + type ix_type is (reset_ix, load_ix, pull_lo_ix, pull_hi_ix, latch_ix ); + type iy_type is (reset_iy, load_iy, pull_lo_iy, pull_hi_iy, latch_iy ); + type sp_type is (reset_sp, latch_sp, load_sp, pull_hi_sp, pull_lo_sp ); + type up_type is (reset_up, latch_up, load_up, pull_hi_up, pull_lo_up ); + type pc_type is (reset_pc, latch_pc, load_pc, pull_lo_pc, pull_hi_pc, incr_pc ); + type md_type is (reset_md, latch_md, load_md, fetch_first_md, fetch_next_md, shiftl_md ); + type ea_type is (reset_ea, latch_ea, load_ea, fetch_first_ea, fetch_next_ea ); + type left_type is (cc_left, acca_left, accb_left, dp_left, + ix_left, iy_left, up_left, sp_left, + accd_left, md_left, pc_left, ea_left ); + type right_type is (ea_right, zero_right, one_right, two_right, + acca_right, accb_right, accd_right, + md_right, md_sign5_right, md_sign8_right ); + type alu_type is (alu_add8, alu_sub8, alu_add16, alu_sub16, alu_adc, alu_sbc, + alu_and, alu_ora, alu_eor, + alu_tst, alu_inc, alu_dec, alu_clr, alu_neg, alu_com, + alu_lsr16, alu_lsl16, + alu_ror8, alu_rol8, alu_mul, + alu_asr8, alu_asl8, alu_lsr8, + alu_andcc, alu_orcc, alu_sex, alu_tfr, alu_abx, + alu_seif, alu_sei, alu_see, alu_cle, + alu_ld8, alu_st8, alu_ld16, alu_st16, alu_lea, alu_nop, alu_daa ); + + signal op_code: std_logic_vector(7 downto 0); + signal pre_code: std_logic_vector(7 downto 0); + signal acca: std_logic_vector(7 downto 0); + signal accb: std_logic_vector(7 downto 0); + signal cc: std_logic_vector(7 downto 0); + signal cc_out: std_logic_vector(7 downto 0); + signal dp: std_logic_vector(7 downto 0); + signal xreg: std_logic_vector(15 downto 0); + signal yreg: std_logic_vector(15 downto 0); + signal sp: std_logic_vector(15 downto 0); + signal up: std_logic_vector(15 downto 0); + signal ea: std_logic_vector(15 downto 0); + signal pc: std_logic_vector(15 downto 0); + signal md: std_logic_vector(15 downto 0); + signal left: std_logic_vector(15 downto 0); + signal right: std_logic_vector(15 downto 0); + signal out_alu: std_logic_vector(15 downto 0); + signal iv: std_logic_vector(2 downto 0); + signal nmi_req: std_logic; + signal nmi_ack: std_logic; + signal nmi_enable: std_logic; + signal fic: std_logic; -- first instruction cycle + signal lic: std_logic; -- last instruction cycle + + signal state: state_type; + signal next_state: state_type; + signal return_state: state_type; + signal saved_state: state_type; + signal st_ctrl: st_type; + signal iv_ctrl: iv_type; + signal pc_ctrl: pc_type; + signal ea_ctrl: ea_type; + signal op_ctrl: op_type; + signal pre_ctrl: pre_type; + signal md_ctrl: md_type; + signal acca_ctrl: acca_type; + signal accb_ctrl: accb_type; + signal ix_ctrl: ix_type; + signal iy_ctrl: iy_type; + signal cc_ctrl: cc_type; + signal dp_ctrl: dp_type; + signal sp_ctrl: sp_type; + signal up_ctrl: up_type; + signal left_ctrl: left_type; + signal right_ctrl: right_type; + signal alu_ctrl: alu_type; + signal addr_ctrl: addr_type; + signal dout_ctrl: dout_type; + + +begin + +---------------------------------- +-- +-- State machine stack +-- +---------------------------------- +--state_stack_proc: process( clk, hold, state_stack, st_ctrl, +-- return_state, fetch_state ) +state_stack_proc: process( clk, st_ctrl, return_state ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case st_ctrl is + when reset_st => + saved_state <= fetch_state; + when push_st => + saved_state <= return_state; + when others => + null; + end case; + end if; + end if; +end process; + +---------------------------------- +-- +-- Interrupt Vector control +-- +---------------------------------- +-- +int_vec_proc: process( clk, iv_ctrl ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case iv_ctrl is + when reset_iv => + iv <= RST_VEC; + when nmi_iv => + iv <= NMI_VEC; + when swi_iv => + iv <= SWI_VEC; + when irq_iv => + iv <= IRQ_VEC; + when firq_iv => + iv <= FIRQ_VEC; + when swi2_iv => + iv <= SWI2_VEC; + when swi3_iv => + iv <= SWI3_VEC; + when others => + null; + end case; + end if; -- hold + end if; -- clk +end process; + +---------------------------------- +-- +-- Program Counter Control +-- +---------------------------------- + +--pc_reg: process( clk, pc_ctrl, hold, pc, out_alu, data_in ) +pc_reg: process( clk ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case pc_ctrl is + when reset_pc => + pc <= (others=>'0'); + when load_pc => + pc <= out_alu(15 downto 0); + when pull_lo_pc => + pc(7 downto 0) <= data_in; + when pull_hi_pc => + pc(15 downto 8) <= data_in; + when incr_pc => + pc <= pc + 1; + when others => + null; + end case; + end if; + end if; +end process; + +---------------------------------- +-- +-- Effective Address Control +-- +---------------------------------- + +--ea_reg: process( clk, ea_ctrl, hold, ea, out_alu, data_in, dp ) +ea_reg: process( clk ) +begin + + if clk'event and clk = '0' then + if hold= '0' then + case ea_ctrl is + when reset_ea => + ea <= (others=>'0'); + when fetch_first_ea => + ea(7 downto 0) <= data_in; + ea(15 downto 8) <= dp; + when fetch_next_ea => + ea(15 downto 8) <= ea(7 downto 0); + ea(7 downto 0) <= data_in; + when load_ea => + ea <= out_alu(15 downto 0); + when others => + null; + end case; + end if; + end if; +end process; + +-------------------------------- +-- +-- Accumulator A +-- +-------------------------------- +--acca_reg : process( clk, acca_ctrl, hold, out_alu, acca, data_in ) +acca_reg : process( clk ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case acca_ctrl is + when reset_acca => + acca <= (others=>'0'); + when load_acca => + acca <= out_alu(7 downto 0); + when load_hi_acca => + acca <= out_alu(15 downto 8); + when pull_acca => + acca <= data_in; + when others => + null; + end case; + end if; + end if; +end process; + +-------------------------------- +-- +-- Accumulator B +-- +-------------------------------- +--accb_reg : process( clk, accb_ctrl, hold, out_alu, accb, data_in ) +accb_reg : process( clk ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case accb_ctrl is + when reset_accb => + accb <= (others=>'0'); + when load_accb => + accb <= out_alu(7 downto 0); + when pull_accb => + accb <= data_in; + when others => + null; + end case; + end if; + end if; +end process; + +-------------------------------- +-- +-- X Index register +-- +-------------------------------- +--ix_reg : process( clk, ix_ctrl, hold, out_alu, xreg, data_in ) +ix_reg : process( clk ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case ix_ctrl is + when reset_ix => + xreg <= (others=>'0'); + when load_ix => + xreg <= out_alu(15 downto 0); + when pull_hi_ix => + xreg(15 downto 8) <= data_in; + when pull_lo_ix => + xreg(7 downto 0) <= data_in; + when others => + null; + end case; + end if; + end if; +end process; + +-------------------------------- +-- +-- Y Index register +-- +-------------------------------- +--iy_reg : process( clk, iy_ctrl, hold, out_alu, yreg, data_in ) +iy_reg : process( clk ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case iy_ctrl is + when reset_iy => + yreg <= (others=>'0'); + when load_iy => + yreg <= out_alu(15 downto 0); + when pull_hi_iy => + yreg(15 downto 8) <= data_in; + when pull_lo_iy => + yreg(7 downto 0) <= data_in; + when others => + null; + end case; + end if; + end if; +end process; + +-------------------------------- +-- +-- S stack pointer +-- +-------------------------------- +--sp_reg : process( clk, sp_ctrl, hold, sp, out_alu, data_in, nmi_enable ) +sp_reg : process( clk ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case sp_ctrl is + when reset_sp => + sp <= (others=>'0'); + nmi_enable <= '0'; + when load_sp => + sp <= out_alu(15 downto 0); + nmi_enable <= '1'; + when pull_hi_sp => + sp(15 downto 8) <= data_in; + when pull_lo_sp => + sp(7 downto 0) <= data_in; + nmi_enable <= '1'; + when others => + null; + end case; + end if; + end if; +end process; + +-------------------------------- +-- +-- U stack pointer +-- +-------------------------------- +--up_reg : process( clk, up_ctrl, hold, up, out_alu, data_in ) +up_reg : process( clk ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case up_ctrl is + when reset_up => + up <= (others=>'0'); + when load_up => + up <= out_alu(15 downto 0); + when pull_hi_up => + up(15 downto 8) <= data_in; + when pull_lo_up => + up(7 downto 0) <= data_in; + when others => + null; + end case; + end if; + end if; +end process; + +-------------------------------- +-- +-- Memory Data +-- +-------------------------------- +--md_reg : process( clk, md_ctrl, hold, out_alu, data_in, md ) +md_reg : process( clk ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case md_ctrl is + when reset_md => + md <= (others=>'0'); + when load_md => + md <= out_alu(15 downto 0); + when fetch_first_md => -- sign extend md for branches + md(15 downto 8) <= data_in(7) & data_in(7) & data_in(7) & data_in(7) & + data_in(7) & data_in(7) & data_in(7) & data_in(7) ; + md(7 downto 0) <= data_in; + when fetch_next_md => + md(15 downto 8) <= md(7 downto 0); + md(7 downto 0) <= data_in; + when shiftl_md => + md(15 downto 1) <= md(14 downto 0); + md(0) <= '0'; + when others => + null; + end case; + end if; + end if; +end process; + + +---------------------------------- +-- +-- Condition Codes +-- +---------------------------------- + +--cc_reg: process( clk, cc_ctrl, hold, cc_out, cc, data_in ) +cc_reg: process( clk ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case cc_ctrl is + when reset_cc => + cc <= "11010000"; -- set EBIT, FBIT & IBIT + when load_cc => + cc <= cc_out; + when pull_cc => + cc <= data_in; + when others => + null; + end case; + end if; + end if; +end process; + +---------------------------------- +-- +-- Direct Page register +-- +---------------------------------- + +--dp_reg: process( clk, dp_ctrl, hold, out_alu, dp, data_in ) +dp_reg: process( clk ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case dp_ctrl is + when reset_dp => + dp <= (others=>'0'); + when load_dp => + dp <= out_alu(7 downto 0); + when pull_dp => + dp <= data_in; + when others => + null; + end case; + end if; + end if; +end process; + + +---------------------------------- +-- +-- op code register +-- +---------------------------------- + +--op_reg: process( clk, op_ctrl, hold, op_code, data_in ) +op_reg: process( clk ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case op_ctrl is + when reset_op => + op_code <= "00010010"; + when fetch_op => + op_code <= data_in; + when others => + null; + end case; + end if; + end if; +end process; + + +---------------------------------- +-- +-- pre byte op code register +-- +---------------------------------- + +--pre_reg: process( clk, pre_ctrl, hold, pre_code, data_in ) +pre_reg: process( clk ) +begin + if clk'event and clk = '0' then + if hold = '0' then + case pre_ctrl is + when reset_pre => + pre_code <= (others=>'0'); + when fetch_pre => + pre_code <= data_in; + when load_pre => + pre_code <= op_code; + when others => + null; + end case; + end if; + end if; +end process; + +-------------------------------- +-- +-- state machine +-- +-------------------------------- + +--change_state: process( clk, rst, state, hold, next_state ) +change_state: process( clk ) +begin + if clk'event and clk = '0' then + if rst = '1' then + fic <= '0'; + nmi_ack <= '0'; + state <= reset_state; + elsif hold = '0' then + fic <= lic; + -- + -- nmi request is not cleared until nmi input goes low + -- + if (nmi_req = '0') and (nmi_ack='1') then + nmi_ack <= '0'; + end if; + + if (nmi_req = '1') and (nmi_ack = '0') and (state = int_nmimask_state) then + nmi_ack <= '1'; + end if; + + if lic = '1' then + if halt = '1' then + state <= halt_state; + + -- service non maskable interrupts + elsif (nmi_req = '1') and (nmi_ack = '0') then + state <= int_nmi_state; + -- + -- FIRQ & IRQ are level sensitive + -- + elsif (firq = '1') and (cc(FBIT) = '0') then + state <= int_firq_state; + + elsif (irq = '1') and (cc(IBIT) = '0') then + state <= int_irq_state; + -- + -- Version 1.27 2015-05-30 + -- Exit sync_state on masked interrupt. + -- + -- Version 1.28 2015-05-30 + -- Move this code to the state sequencer + -- near line 5566. + -- + -- elsif (state = sync_state) and ((firq = '1') or (irq = '1'))then + -- state <= fetch_state; + -- + else + state <= next_state; + end if; -- halt, nmi, firq, irq + else + state <= next_state; + end if; -- lic + end if; -- reset/hold + end if; -- clk +end process; + +------------------------------------ +-- +-- Detect Edge of NMI interrupt +-- +------------------------------------ + +--nmi_handler : process( clk, rst, nmi, nmi_ack, nmi_req, nmi_enable ) +nmi_handler : process( rst, clk ) +begin + if rst='1' then + nmi_req <= '0'; + elsif clk'event and clk='0' then + if (nmi='1') and (nmi_ack='0') and (nmi_enable='1') then + nmi_req <= '1'; + else + if (nmi='0') and (nmi_ack='1') then + nmi_req <= '0'; + end if; + end if; + end if; +end process; + + +---------------------------------- +-- +-- Address output multiplexer +-- +---------------------------------- + +addr_mux: process( addr_ctrl, pc, ea, up, sp, iv ) +begin + ifetch <= '0'; + vma <= '1'; + case addr_ctrl is + when fetch_ad => + addr <= pc; + rw <= '1'; + ifetch <= '1'; + when read_ad => + addr <= ea; + rw <= '1'; + when write_ad => + addr <= ea; + rw <= '0'; + when pushs_ad => + addr <= sp; + rw <= '0'; + when pulls_ad => + addr <= sp; + rw <= '1'; + when pushu_ad => + addr <= up; + rw <= '0'; + when pullu_ad => + addr <= up; + rw <= '1'; + when int_hi_ad => + addr <= "111111111111" & iv & "0"; + rw <= '1'; + when int_lo_ad => + addr <= "111111111111" & iv & "1"; + rw <= '1'; + when others => + addr <= "1111111111111111"; + rw <= '1'; + vma <= '0'; + end case; +end process; + +-------------------------------- +-- +-- Data Bus output +-- +-------------------------------- +dout_mux : process( dout_ctrl, md, acca, accb, dp, xreg, yreg, sp, up, pc, cc ) +begin + case dout_ctrl is + when cc_dout => -- condition code register + data_out <= cc; + when acca_dout => -- accumulator a + data_out <= acca; + when accb_dout => -- accumulator b + data_out <= accb; + when dp_dout => -- direct page register + data_out <= dp; + when ix_lo_dout => -- X index reg + data_out <= xreg(7 downto 0); + when ix_hi_dout => -- X index reg + data_out <= xreg(15 downto 8); + when iy_lo_dout => -- Y index reg + data_out <= yreg(7 downto 0); + when iy_hi_dout => -- Y index reg + data_out <= yreg(15 downto 8); + when up_lo_dout => -- U stack pointer + data_out <= up(7 downto 0); + when up_hi_dout => -- U stack pointer + data_out <= up(15 downto 8); + when sp_lo_dout => -- S stack pointer + data_out <= sp(7 downto 0); + when sp_hi_dout => -- S stack pointer + data_out <= sp(15 downto 8); + when md_lo_dout => -- alu output + data_out <= md(7 downto 0); + when md_hi_dout => -- alu output + data_out <= md(15 downto 8); + when pc_lo_dout => -- low order pc + data_out <= pc(7 downto 0); + when pc_hi_dout => -- high order pc + data_out <= pc(15 downto 8); + end case; +end process; + +---------------------------------- +-- +-- Left Mux +-- +---------------------------------- + +left_mux: process( left_ctrl, acca, accb, cc, dp, xreg, yreg, up, sp, pc, ea, md ) +begin + case left_ctrl is + when cc_left => + left(15 downto 8) <= "00000000"; + left(7 downto 0) <= cc; + when acca_left => + left(15 downto 8) <= "00000000"; + left(7 downto 0) <= acca; + when accb_left => + left(15 downto 8) <= "00000000"; + left(7 downto 0) <= accb; + when dp_left => + left(15 downto 8) <= "00000000"; + left(7 downto 0) <= dp; + when accd_left => + left(15 downto 8) <= acca; + left(7 downto 0) <= accb; + when md_left => + left <= md; + when ix_left => + left <= xreg; + when iy_left => + left <= yreg; + when sp_left => + left <= sp; + when up_left => + left <= up; + when pc_left => + left <= pc; + when others => +-- when ea_left => + left <= ea; + end case; +end process; + +---------------------------------- +-- +-- Right Mux +-- +---------------------------------- + +right_mux: process( right_ctrl, md, acca, accb, ea ) +begin + case right_ctrl is + when ea_right => + right <= ea; + when zero_right => + right <= "0000000000000000"; + when one_right => + right <= "0000000000000001"; + when two_right => + right <= "0000000000000010"; + when acca_right => + if acca(7) = '0' then + right <= "00000000" & acca(7 downto 0); + else + right <= "11111111" & acca(7 downto 0); + end if; + when accb_right => + if accb(7) = '0' then + right <= "00000000" & accb(7 downto 0); + else + right <= "11111111" & accb(7 downto 0); + end if; + when accd_right => + right <= acca & accb; + when md_sign5_right => + if md(4) = '0' then + right <= "00000000000" & md(4 downto 0); + else + right <= "11111111111" & md(4 downto 0); + end if; + when md_sign8_right => + if md(7) = '0' then + right <= "00000000" & md(7 downto 0); + else + right <= "11111111" & md(7 downto 0); + end if; + when others => +-- when md_right => + right <= md; + end case; +end process; + +---------------------------------- +-- +-- Arithmetic Logic Unit +-- +---------------------------------- + +alu: process( alu_ctrl, cc, left, right, out_alu, cc_out ) +variable valid_lo, valid_hi : boolean; +variable carry_in : std_logic; +variable daa_reg : std_logic_vector(7 downto 0); +begin + + case alu_ctrl is + when alu_adc | alu_sbc | + alu_rol8 | alu_ror8 => + carry_in := cc(CBIT); + when alu_asr8 => + carry_in := left(7); + when others => + carry_in := '0'; + end case; + + valid_lo := left(3 downto 0) <= 9; + valid_hi := left(7 downto 4) <= 9; + + -- + -- CBIT HBIT VHI VLO DAA + -- 0 0 0 0 66 (!VHI : hi_nybble>8) + -- 0 0 0 1 60 + -- 0 0 1 1 00 + -- 0 0 1 0 06 ( VHI : hi_nybble<=8) + -- + -- 0 1 1 0 06 + -- 0 1 1 1 06 + -- 0 1 0 1 66 + -- 0 1 0 0 66 + -- + -- 1 1 0 0 66 + -- 1 1 0 1 66 + -- 1 1 1 1 66 + -- 1 1 1 0 66 + -- + -- 1 0 1 0 66 + -- 1 0 1 1 60 + -- 1 0 0 1 60 + -- 1 0 0 0 66 + -- + -- 66 = (!VHI & !VLO) + (CBIT & HBIT) + (HBIT & !VHI) + (CBIT & !VLO) + -- = (CBIT & (HBIT + !VLO)) + (!VHI & (HBIT + !VLO)) + -- = (!VLO & (CBIT + !VHI)) + (HBIT & (CBIT + !VHI)) + -- 60 = (CBIT & !HBIT & VLO) + (!HBIT & !VHI & VLO) + -- = (!HBIT & VLO & (CBIT + !VHI)) + -- 06 = (!CBIT & VHI & (!VLO + VHI) + -- 00 = (!CBIT & !HBIT & VHI & VLO) + -- + if (cc(CBIT) = '0') then + -- CBIT=0 + if( cc(HBIT) = '0' ) then + -- HBIT=0 + if valid_lo then + -- lo <= 9 (no overflow in low nybble) + if valid_hi then + -- hi <= 9 (no overflow in either low or high nybble) + daa_reg := "00000000"; + else + -- hi > 9 (overflow in high nybble only) + daa_reg := "01100000"; + end if; + else + -- lo > 9 (overflow in low nybble) + -- + -- since there is already an overflow in the low nybble + -- you need to make room in the high nybble for the low nybble carry + -- so compare the high nybble with 8 rather than 9 + -- if the high nybble is 9 there will be an overflow on the high nybble + -- after the decimal adjust which means it will roll over to an invalid BCD digit + -- + if( left(7 downto 4) <= 8 ) then + -- hi <= 8 (overflow in low nybble only) + daa_reg := "00000110"; + else + -- hi > 8 (overflow in low and high nybble) + daa_reg := "01100110"; + end if; + end if; + else + -- HBIT=1 (overflow in low nybble) + if valid_hi then + -- hi <= 9 (overflow in low nybble only) + daa_reg := "00000110"; + else + -- hi > 9 (overflow in low and high nybble) + daa_reg := "01100110"; + end if; + end if; + else + -- CBIT=1 (carry => overflow in high nybble) + if ( cc(HBIT) = '0' )then + -- HBIT=0 (half carry clear => may or may not be an overflow in the low nybble) + if valid_lo then + -- lo <=9 (overflow in high nybble only) + daa_reg := "01100000"; + else + -- lo >9 (overflow in low and high nybble) + daa_reg := "01100110"; + end if; + else + -- HBIT=1 (overflow in low and high nybble) + daa_reg := "01100110"; + end if; + end if; + + case alu_ctrl is + when alu_add8 | alu_inc | + alu_add16 | alu_adc | alu_mul => + out_alu <= left + right + ("000000000000000" & carry_in); + when alu_sub8 | alu_dec | + alu_sub16 | alu_sbc => + out_alu <= left - right - ("000000000000000" & carry_in); + when alu_abx => + out_alu <= left + ("00000000" & right(7 downto 0)) ; + when alu_and => + out_alu <= left and right; -- and/bit + when alu_ora => + out_alu <= left or right; -- or + when alu_eor => + out_alu <= left xor right; -- eor/xor + when alu_lsl16 | alu_asl8 | alu_rol8 => + out_alu <= left(14 downto 0) & carry_in; -- rol8/asl8/lsl16 + when alu_lsr16 => + out_alu <= carry_in & left(15 downto 1); -- lsr16 + when alu_lsr8 | alu_asr8 | alu_ror8 => + out_alu <= "00000000" & carry_in & left(7 downto 1); -- ror8/asr8/lsr8 + when alu_neg => + out_alu <= right - left; -- neg (right=0) + when alu_com => + out_alu <= not left; + when alu_clr | alu_ld8 | alu_ld16 | alu_lea => + out_alu <= right; -- clr, ld + when alu_st8 | alu_st16 | alu_andcc | alu_orcc | alu_tfr => + out_alu <= left; + when alu_daa => + out_alu <= left + ("00000000" & daa_reg); + when alu_sex => + if left(7) = '0' then + out_alu <= "00000000" & left(7 downto 0); + else + out_alu <= "11111111" & left(7 downto 0); + end if; + when others => + out_alu <= left; -- nop + end case; + + -- + -- carry bit + -- + case alu_ctrl is + when alu_add8 | alu_adc => + cc_out(CBIT) <= (left(7) and right(7)) or + (left(7) and not out_alu(7)) or + (right(7) and not out_alu(7)); + when alu_sub8 | alu_sbc => + cc_out(CBIT) <= ((not left(7)) and right(7)) or + ((not left(7)) and out_alu(7)) or + (right(7) and out_alu(7)); + when alu_add16 => + cc_out(CBIT) <= (left(15) and right(15)) or + (left(15) and not out_alu(15)) or + (right(15) and not out_alu(15)); + when alu_sub16 => + cc_out(CBIT) <= ((not left(15)) and right(15)) or + ((not left(15)) and out_alu(15)) or + (right(15) and out_alu(15)); + when alu_ror8 | alu_lsr16 | alu_lsr8 | alu_asr8 => + cc_out(CBIT) <= left(0); + when alu_rol8 | alu_asl8 => + cc_out(CBIT) <= left(7); + when alu_lsl16 => + cc_out(CBIT) <= left(15); + when alu_com => + cc_out(CBIT) <= '1'; + when alu_neg | alu_clr => + cc_out(CBIT) <= out_alu(7) or out_alu(6) or out_alu(5) or out_alu(4) or + out_alu(3) or out_alu(2) or out_alu(1) or out_alu(0); + when alu_mul => + cc_out(CBIT) <= out_alu(7); + when alu_daa => + if ( daa_reg(7 downto 4) = "0110" ) then + cc_out(CBIT) <= '1'; + else + cc_out(CBIT) <= '0'; + end if; + when alu_andcc => + cc_out(CBIT) <= left(CBIT) and cc(CBIT); + when alu_orcc => + cc_out(CBIT) <= left(CBIT) or cc(CBIT); + when alu_tfr => + cc_out(CBIT) <= left(CBIT); + when others => + cc_out(CBIT) <= cc(CBIT); + end case; + -- + -- Zero flag + -- + case alu_ctrl is + when alu_add8 | alu_sub8 | + alu_adc | alu_sbc | + alu_and | alu_ora | alu_eor | + alu_inc | alu_dec | + alu_neg | alu_com | alu_clr | + alu_rol8 | alu_ror8 | alu_asr8 | alu_asl8 | alu_lsr8 | + alu_ld8 | alu_st8 | alu_sex | alu_daa => + cc_out(ZBIT) <= not( out_alu(7) or out_alu(6) or out_alu(5) or out_alu(4) or + out_alu(3) or out_alu(2) or out_alu(1) or out_alu(0) ); + when alu_add16 | alu_sub16 | alu_mul | + alu_lsl16 | alu_lsr16 | + alu_ld16 | alu_st16 | alu_lea => + cc_out(ZBIT) <= not( out_alu(15) or out_alu(14) or out_alu(13) or out_alu(12) or + out_alu(11) or out_alu(10) or out_alu(9) or out_alu(8) or + out_alu(7) or out_alu(6) or out_alu(5) or out_alu(4) or + out_alu(3) or out_alu(2) or out_alu(1) or out_alu(0) ); + when alu_andcc => + cc_out(ZBIT) <= left(ZBIT) and cc(ZBIT); + when alu_orcc => + cc_out(ZBIT) <= left(ZBIT) or cc(ZBIT); + when alu_tfr => + cc_out(ZBIT) <= left(ZBIT); + when others => + cc_out(ZBIT) <= cc(ZBIT); + end case; + + -- + -- negative flag + -- + case alu_ctrl is + when alu_add8 | alu_sub8 | + alu_adc | alu_sbc | + alu_and | alu_ora | alu_eor | + alu_rol8 | alu_ror8 | alu_asr8 | alu_asl8 | alu_lsr8 | + alu_inc | alu_dec | alu_neg | alu_com | alu_clr | + alu_ld8 | alu_st8 | alu_sex | alu_daa => + cc_out(NBIT) <= out_alu(7); + when alu_add16 | alu_sub16 | + alu_lsl16 | alu_lsr16 | + alu_ld16 | alu_st16 => + cc_out(NBIT) <= out_alu(15); + when alu_andcc => + cc_out(NBIT) <= left(NBIT) and cc(NBIT); + when alu_orcc => + cc_out(NBIT) <= left(NBIT) or cc(NBIT); + when alu_tfr => + cc_out(NBIT) <= left(NBIT); + when others => + cc_out(NBIT) <= cc(NBIT); + end case; + + -- + -- Interrupt mask flag + -- + case alu_ctrl is + when alu_andcc => + cc_out(IBIT) <= left(IBIT) and cc(IBIT); + when alu_orcc => + cc_out(IBIT) <= left(IBIT) or cc(IBIT); + when alu_tfr => + cc_out(IBIT) <= left(IBIT); + when alu_seif | alu_sei => + cc_out(IBIT) <= '1'; + when others => + cc_out(IBIT) <= cc(IBIT); -- interrupt mask + end case; + + -- + -- Half Carry flag + -- + case alu_ctrl is + when alu_add8 | alu_adc => + cc_out(HBIT) <= (left(3) and right(3)) or + (right(3) and not out_alu(3)) or + (left(3) and not out_alu(3)); + when alu_andcc => + cc_out(HBIT) <= left(HBIT) and cc(HBIT); + when alu_orcc => + cc_out(HBIT) <= left(HBIT) or cc(HBIT); + when alu_tfr => + cc_out(HBIT) <= left(HBIT); + when others => + cc_out(HBIT) <= cc(HBIT); + end case; + + -- + -- Overflow flag + -- + case alu_ctrl is + when alu_add8 | alu_adc => + cc_out(VBIT) <= (left(7) and right(7) and (not out_alu(7))) or + ((not left(7)) and (not right(7)) and out_alu(7)); + when alu_sub8 | alu_sbc => + cc_out(VBIT) <= (left(7) and (not right(7)) and (not out_alu(7))) or + ((not left(7)) and right(7) and out_alu(7)); + when alu_add16 => + cc_out(VBIT) <= (left(15) and right(15) and (not out_alu(15))) or + ((not left(15)) and (not right(15)) and out_alu(15)); + when alu_sub16 => + cc_out(VBIT) <= (left(15) and (not right(15)) and (not out_alu(15))) or + ((not left(15)) and right(15) and out_alu(15)); + when alu_inc => + cc_out(VBIT) <= ((not left(7)) and left(6) and left(5) and left(4) and + left(3) and left(2) and left(1) and left(0)); + when alu_dec | alu_neg => + cc_out(VBIT) <= (left(7) and (not left(6)) and (not left(5)) and (not left(4)) and + (not left(3)) and (not left(2)) and (not left(1)) and (not left(0))); +-- 6809 Programming reference manual says +-- V not affected by ASR, LSR and ROR +-- This is different to the 6800 +-- John Kent 6th June 2006 +-- when alu_asr8 => +-- cc_out(VBIT) <= left(0) xor left(7); +-- when alu_lsr8 | alu_lsr16 => +-- cc_out(VBIT) <= left(0); +-- when alu_ror8 => +-- cc_out(VBIT) <= left(0) xor cc(CBIT); + when alu_lsl16 => + cc_out(VBIT) <= left(15) xor left(14); + when alu_rol8 | alu_asl8 => + cc_out(VBIT) <= left(7) xor left(6); +-- +-- 11th July 2006 - John Kent +-- What DAA does with V is anyones guess +-- It is undefined in the 6809 programming manual +-- + when alu_daa => + cc_out(VBIT) <= left(7) xor out_alu(7) xor cc(CBIT); +-- CLR resets V Bit +-- John Kent 6th June 2006 + when alu_and | alu_ora | alu_eor | alu_com | alu_clr | + alu_st8 | alu_st16 | alu_ld8 | alu_ld16 | alu_sex => + cc_out(VBIT) <= '0'; + when alu_andcc => + cc_out(VBIT) <= left(VBIT) and cc(VBIT); + when alu_orcc => + cc_out(VBIT) <= left(VBIT) or cc(VBIT); + when alu_tfr => + cc_out(VBIT) <= left(VBIT); + when others => + cc_out(VBIT) <= cc(VBIT); + end case; + + case alu_ctrl is + when alu_andcc => + cc_out(FBIT) <= left(FBIT) and cc(FBIT); + when alu_orcc => + cc_out(FBIT) <= left(FBIT) or cc(FBIT); + when alu_tfr => + cc_out(FBIT) <= left(FBIT); + when alu_seif => + cc_out(FBIT) <= '1'; + when others => + cc_out(FBIT) <= cc(FBIT); + end case; + + case alu_ctrl is + when alu_andcc => + cc_out(EBIT) <= left(EBIT) and cc(EBIT); + when alu_orcc => + cc_out(EBIT) <= left(EBIT) or cc(EBIT); + when alu_tfr => + cc_out(EBIT) <= left(EBIT); + when alu_see => + cc_out(EBIT) <= '1'; + when alu_cle => + cc_out(EBIT) <= '0'; + when others => + cc_out(EBIT) <= cc(EBIT); + end case; +end process; + +------------------------------------ +-- +-- state sequencer +-- +------------------------------------ +process( state, saved_state, + op_code, pre_code, + cc, ea, md, iv, fic, halt, + nmi_req, firq, irq, lic ) +variable cond_true : boolean; -- variable used to evaluate coditional branches +begin + cond_true := (1=1); + ba <= '0'; + bs <= '0'; + lic <= '0'; + opfetch <= '0'; + iv_ctrl <= latch_iv; + -- Registers preserved + cc_ctrl <= latch_cc; + acca_ctrl <= latch_acca; + accb_ctrl <= latch_accb; + dp_ctrl <= latch_dp; + ix_ctrl <= latch_ix; + iy_ctrl <= latch_iy; + up_ctrl <= latch_up; + sp_ctrl <= latch_sp; + pc_ctrl <= latch_pc; + md_ctrl <= latch_md; + ea_ctrl <= latch_ea; + op_ctrl <= latch_op; + pre_ctrl <= latch_pre; + -- ALU Idle + left_ctrl <= pc_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_nop; + -- Bus idle + addr_ctrl <= idle_ad; + dout_ctrl <= cc_dout; + -- Next State Fetch + st_ctrl <= idle_st; + return_state <= fetch_state; + next_state <= fetch_state; + + case state is + when reset_state => -- released from reset + -- reset the registers + iv_ctrl <= reset_iv; + op_ctrl <= reset_op; + pre_ctrl <= reset_pre; + cc_ctrl <= reset_cc; + acca_ctrl <= reset_acca; + accb_ctrl <= reset_accb; + dp_ctrl <= reset_dp; + ix_ctrl <= reset_ix; + iy_ctrl <= reset_iy; + up_ctrl <= reset_up; + sp_ctrl <= reset_sp; + pc_ctrl <= reset_pc; + ea_ctrl <= reset_ea; + md_ctrl <= reset_md; + st_ctrl <= reset_st; + next_state <= vect_hi_state; + + -- + -- Jump via interrupt vector + -- iv holds interrupt type + -- fetch PC hi from vector location + -- + when vect_hi_state => + -- fetch pc low interrupt vector + pc_ctrl <= pull_hi_pc; + addr_ctrl <= int_hi_ad; + bs <= '1'; + next_state <= vect_lo_state; + + -- + -- jump via interrupt vector + -- iv holds vector type + -- fetch PC lo from vector location + -- + when vect_lo_state => + -- fetch the vector low byte + pc_ctrl <= pull_lo_pc; + addr_ctrl <= int_lo_ad; + bs <= '1'; + next_state <= fetch_state; + + when vect_idle_state => + -- + -- Last Instruction Cycle for SWI, SWI2 & SWI3 + -- + if op_code = "00111111" then + lic <= '1'; + end if; + next_state <= fetch_state; + + -- + -- Here to fetch an instruction + -- PC points to opcode + -- + when fetch_state => + -- fetch the op code + opfetch <= '1'; + op_ctrl <= fetch_op; + pre_ctrl <= fetch_pre; + ea_ctrl <= reset_ea; + -- Fetch op code + addr_ctrl <= fetch_ad; + -- Advance the PC to fetch next instruction byte + pc_ctrl <= incr_pc; + next_state <= decode_state; + + -- + -- Here to decode instruction + -- and fetch next byte of intruction + -- whether it be necessary or not + -- + when decode_state => + -- fetch first byte of address or immediate data + ea_ctrl <= fetch_first_ea; + md_ctrl <= fetch_first_md; + addr_ctrl <= fetch_ad; + case op_code(7 downto 4) is + -- + -- direct single op (2 bytes) + -- 6809 => 6 cycles + -- cpu09 => 5 cycles + -- 1 op=(pc) / pc=pc+1 + -- 2 ea_hi=dp / ea_lo=(pc) / pc=pc+1 + -- 3 md_lo=(ea) / pc=pc + -- 4 alu_left=md / md=alu_out / pc=pc + -- 5 (ea)=md_lo / pc=pc + -- + -- Exception is JMP + -- 6809 => 3 cycles + -- cpu09 => 3 cycles + -- 1 op=(pc) / pc=pc+1 + -- 2 ea_hi=dp / ea_lo=(pc) / pc=pc+1 + -- 3 pc=ea + -- + when "0000" => + -- advance the PC + pc_ctrl <= incr_pc; + + case op_code(3 downto 0) is + when "1110" => -- jmp + next_state <= jmp_state; + + when "1111" => -- clr + next_state <= single_op_exec_state; + + when others => + next_state <= single_op_read_state; + + end case; + + -- acca / accb inherent instructions + when "0001" => + case op_code(3 downto 0) is + -- + -- Page2 pre byte + -- pre=(pc) / pc=pc+1 + -- op=(pc) / pc=pc+1 + -- + when "0000" => -- page2 + opfetch <= '1'; + op_ctrl <= fetch_op; + pre_ctrl <= load_pre; + -- advance pc + pc_ctrl <= incr_pc; + next_state <= decode_state; + + -- + -- Page3 pre byte + -- pre=(pc) / pc=pc+1 + -- op=(pc) / pc=pc+1 + -- + when "0001" => -- page3 + opfetch <= '1'; + op_ctrl <= fetch_op; + pre_ctrl <= load_pre; + -- advance pc + pc_ctrl <= incr_pc; + next_state <= decode_state; + + -- + -- nop - No operation ( 1 byte ) + -- 6809 => 2 cycles + -- cpu09 => 2 cycles + -- 1 op=(pc) / pc=pc+1 + -- 2 decode + -- + when "0010" => -- nop + lic <= '1'; + next_state <= fetch_state; + + -- + -- sync - halt execution until an interrupt is received + -- interrupt may be NMI, IRQ or FIRQ + -- program execution continues if the + -- interrupt is asserted for 3 clock cycles + -- note that registers are not pushed onto the stack + -- CPU09 => Interrupts need only be asserted for one clock cycle + -- + when "0011" => -- sync + next_state <= sync_state; + + -- + -- lbra -- long branch (3 bytes) + -- 6809 => 5 cycles + -- cpu09 => 4 cycles + -- 1 op=(pc) / pc=pc+1 + -- 2 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1 + -- 3 md_hi=md_lo / md_lo=(pc) / pc=pc+1 + -- 4 pc=pc+md + -- + when "0110" => + -- increment the pc + pc_ctrl <= incr_pc; + next_state <= lbranch_state; + + -- + -- lbsr - long branch to subroutine (3 bytes) + -- 6809 => 9 cycles + -- cpu09 => 6 cycles + -- 1 op=(pc) /pc=pc+1 + -- 2 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1 / sp=sp-1 + -- 3 md_hi=md_lo / md_lo=(pc) / pc=pc+1 + -- 4 (sp)= pc_lo / sp=sp-1 / pc=pc + -- 5 (sp)=pc_hi / pc=pc + -- 6 pc=pc+md + -- + when "0111" => + -- pre decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- increment the pc + pc_ctrl <= incr_pc; + next_state <= lbranch_state; + + -- + -- Decimal Adjust Accumulator + -- + when "1001" => -- daa + left_ctrl <= acca_left; + right_ctrl <= accb_right; + alu_ctrl <= alu_daa; + cc_ctrl <= load_cc; + acca_ctrl <= load_acca; + lic <= '1'; + next_state <= fetch_state; + + -- + -- OR Condition Codes + -- + when "1010" => -- orcc + -- increment the pc + pc_ctrl <= incr_pc; + next_state <= orcc_state; + + -- + -- AND Condition Codes + -- + when "1100" => -- andcc + -- increment the pc + pc_ctrl <= incr_pc; + next_state <= andcc_state; + + -- + -- Sign Extend + -- + when "1101" => -- sex + left_ctrl <= accb_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_sex; + cc_ctrl <= load_cc; + acca_ctrl <= load_hi_acca; + lic <= '1'; + next_state <= fetch_state; + + -- + -- Exchange Registers + -- + when "1110" => -- exg + -- increment the pc + pc_ctrl <= incr_pc; + next_state <= exg_state; + + -- + -- Transfer Registers + -- + when "1111" => -- tfr + -- increment the pc + pc_ctrl <= incr_pc; + next_state <= tfr_state; + + when others => + -- increment the pc + pc_ctrl <= incr_pc; + lic <= '1'; + next_state <= fetch_state; + end case; + + -- + -- conditional branch + -- + when "0010" => -- branch conditional + -- increment the pc + pc_ctrl <= incr_pc; + case pre_code is + when "00010000" => -- page 2 + -- + -- lbcc -- long branch conditional + -- 6809 => branch 6 cycles, no branch 5 cycles + -- cpu09 => always 5 cycles + -- 1 pre=(pc) / pc=pc+1 + -- 2 op=(pc) / pc=pc+1 + -- 3 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1 + -- 4 md_hi=md_lo / md_lo=(pc) / pc=pc+1 + -- 5 if cond pc=pc+md else pc=pc + -- + next_state <= lbranch_state; + + when others => -- page 1 + -- + -- Short branch conditional + -- 6809 => always 3 cycles + -- cpu09 => always = 3 cycles + -- 1 op=(pc) / pc=pc+1 + -- 2 md_hi=sign(pc) / md_lo=(pc) / pc=pc+1 / test cc + -- 3 if cc tru pc=pc+md else pc=pc + -- + next_state <= sbranch_state; + end case; + + -- + -- Single byte stack operators + -- Do not advance PC + -- + when "0011" => + -- + -- lea - load effective address (2+ bytes) + -- 6809 => 4 cycles + addressing mode + -- cpu09 => 4 cycles + addressing mode + -- 1 op=(pc) / pc=pc+1 + -- 2 md_lo=(pc) / pc=pc+1 + -- 3 calculate ea + -- 4 ix/iy/sp/up = ea + -- + case op_code(3 downto 0) is + when "0000" | -- leax + "0001" | -- leay + "0010" | -- leas + "0011" => -- leau + -- advance PC + pc_ctrl <= incr_pc; + st_ctrl <= push_st; + return_state <= lea_state; + next_state <= indexed_state; + + -- + -- pshs - push registers onto sp stack + -- 6809 => 5 cycles + registers + -- cpu09 => 3 cycles + registers + -- 1 op=(pc) / pc=pc+1 + -- 2 ea_lo=(pc) / pc=pc+1 + -- 3 if ea(7 downto 0) != "00000000" then sp=sp-1 + -- 4 if ea(7) = 1 (sp)=pcl, sp=sp-1 + -- 5 if ea(7) = 1 (sp)=pch + -- if ea(6 downto 0) != "0000000" then sp=sp-1 + -- 6 if ea(6) = 1 (sp)=upl, sp=sp-1 + -- 7 if ea(6) = 1 (sp)=uph + -- if ea(5 downto 0) != "000000" then sp=sp-1 + -- 8 if ea(5) = 1 (sp)=iyl, sp=sp-1 + -- 9 if ea(5) = 1 (sp)=iyh + -- if ea(4 downto 0) != "00000" then sp=sp-1 + -- 10 if ea(4) = 1 (sp)=ixl, sp=sp-1 + -- 11 if ea(4) = 1 (sp)=ixh + -- if ea(3 downto 0) != "0000" then sp=sp-1 + -- 12 if ea(3) = 1 (sp)=dp + -- if ea(2 downto 0) != "000" then sp=sp-1 + -- 13 if ea(2) = 1 (sp)=accb + -- if ea(1 downto 0) != "00" then sp=sp-1 + -- 14 if ea(1) = 1 (sp)=acca + -- if ea(0 downto 0) != "0" then sp=sp-1 + -- 15 if ea(0) = 1 (sp)=cc + -- + when "0100" => -- pshs + -- advance PC + pc_ctrl <= incr_pc; + next_state <= pshs_state; + + -- + -- puls - pull registers of sp stack + -- 6809 => 5 cycles + registers + -- cpu09 => 3 cycles + registers + -- + when "0101" => -- puls + -- advance PC + pc_ctrl <= incr_pc; + next_state <= puls_state; + + -- + -- pshu - push registers onto up stack + -- 6809 => 5 cycles + registers + -- cpu09 => 3 cycles + registers + -- + when "0110" => -- pshu + -- advance PC + pc_ctrl <= incr_pc; + next_state <= pshu_state; + + -- + -- pulu - pull registers of up stack + -- 6809 => 5 cycles + registers + -- cpu09 => 3 cycles + registers + -- + when "0111" => -- pulu + -- advance PC + pc_ctrl <= incr_pc; + next_state <= pulu_state; + + -- + -- rts - return from subroutine + -- 6809 => 5 cycles + -- cpu09 => 4 cycles + -- 1 op=(pc) / pc=pc+1 + -- 2 decode op + -- 3 pc_hi = (sp) / sp=sp+1 + -- 4 pc_lo = (sp) / sp=sp+1 + -- + when "1001" => + next_state <= pull_return_hi_state; + + -- + -- ADD accb to index register + -- *** Note: this is an unsigned addition. + -- does not affect any condition codes + -- 6809 => 3 cycles + -- cpu09 => 2 cycles + -- 1 op=(pc) / pc=pc+1 + -- 2 alu_left=ix / alu_right=accb / ix=alu_out / pc=pc + -- + when "1010" => -- abx + left_ctrl <= ix_left; + right_ctrl <= accb_right; + alu_ctrl <= alu_abx; + ix_ctrl <= load_ix; + lic <= '1'; + next_state <= fetch_state; + + -- + -- Return From Interrupt + -- + when "1011" => -- rti + next_state <= rti_cc_state; + + -- + -- CWAI + -- + when "1100" => -- cwai #$ + -- pre decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- increment pc + pc_ctrl <= incr_pc; + next_state <= cwai_state; + + -- + -- MUL Multiply + -- + when "1101" => -- mul + -- move acca to md + left_ctrl <= acca_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_st16; + md_ctrl <= load_md; -- over ride md_ctrl <= second byte fetch + next_state <= mulea_state; + + -- + -- SWI Software Interrupt + -- Do not advance PC + -- + when "1111" => -- swi + -- predecrement SP + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + st_ctrl <= push_st; + case pre_code is + when "00010000" => -- page 2 + iv_ctrl <= swi2_iv; + return_state <= vect_hi_state; + + when "00010001" => -- page 3 + iv_ctrl <= swi3_iv; + return_state <= vect_hi_state; + + when others => -- page 1 + iv_ctrl <= swi_iv; + return_state <= int_swimask_state; + + end case; + next_state <= int_entire_state; + + when others => + lic <= '1'; + next_state <= fetch_state; + + end case; + -- + -- Accumulator A Single operand + -- source = acca, dest = acca + -- Do not advance PC + -- Typically 2 cycles 1 bytes + -- 1 opcode fetch + -- 2 post byte fetch / instruction decode + -- Note that there is no post byte + -- so do not advance PC in decode cycle + -- Re-run opcode fetch cycle after decode + -- + when "0100" => -- acca single op + left_ctrl <= acca_left; + case op_code(3 downto 0) is + + when "0000" => -- neg + right_ctrl <= zero_right; + alu_ctrl <= alu_neg; + acca_ctrl <= load_acca; + cc_ctrl <= load_cc; + + when "0011" => -- com + right_ctrl <= zero_right; + alu_ctrl <= alu_com; + acca_ctrl <= load_acca; + cc_ctrl <= load_cc; + + when "0100" => -- lsr + right_ctrl <= zero_right; + alu_ctrl <= alu_lsr8; + acca_ctrl <= load_acca; + cc_ctrl <= load_cc; + + when "0110" => -- ror + right_ctrl <= zero_right; + alu_ctrl <= alu_ror8; + acca_ctrl <= load_acca; + cc_ctrl <= load_cc; + + when "0111" => -- asr + right_ctrl <= zero_right; + alu_ctrl <= alu_asr8; + acca_ctrl <= load_acca; + cc_ctrl <= load_cc; + + when "1000" => -- asl + right_ctrl <= zero_right; + alu_ctrl <= alu_asl8; + acca_ctrl <= load_acca; + cc_ctrl <= load_cc; + + when "1001" => -- rol + right_ctrl <= zero_right; + alu_ctrl <= alu_rol8; + acca_ctrl <= load_acca; + cc_ctrl <= load_cc; + + when "1010" => -- dec + right_ctrl <= one_right; + alu_ctrl <= alu_dec; + acca_ctrl <= load_acca; + cc_ctrl <= load_cc; + + when "1011" => -- undefined + right_ctrl <= zero_right; + alu_ctrl <= alu_nop; + acca_ctrl <= latch_acca; + cc_ctrl <= latch_cc; + + when "1100" => -- inc + right_ctrl <= one_right; + alu_ctrl <= alu_inc; + acca_ctrl <= load_acca; + cc_ctrl <= load_cc; + + when "1101" => -- tst + right_ctrl <= zero_right; + alu_ctrl <= alu_st8; + acca_ctrl <= latch_acca; + cc_ctrl <= load_cc; + + when "1110" => -- jmp (not defined) + right_ctrl <= zero_right; + alu_ctrl <= alu_nop; + acca_ctrl <= latch_acca; + cc_ctrl <= latch_cc; + + when "1111" => -- clr + right_ctrl <= zero_right; + alu_ctrl <= alu_clr; + acca_ctrl <= load_acca; + cc_ctrl <= load_cc; + + when others => + right_ctrl <= zero_right; + alu_ctrl <= alu_nop; + acca_ctrl <= latch_acca; + cc_ctrl <= latch_cc; + + end case; + lic <= '1'; + next_state <= fetch_state; + + -- + -- Single Operand accb + -- source = accb, dest = accb + -- Typically 2 cycles 1 bytes + -- 1 opcode fetch + -- 2 post byte fetch / instruction decode + -- Note that there is no post byte + -- so do not advance PC in decode cycle + -- Re-run opcode fetch cycle after decode + -- + when "0101" => + left_ctrl <= accb_left; + case op_code(3 downto 0) is + when "0000" => -- neg + right_ctrl <= zero_right; + alu_ctrl <= alu_neg; + accb_ctrl <= load_accb; + cc_ctrl <= load_cc; + + when "0011" => -- com + right_ctrl <= zero_right; + alu_ctrl <= alu_com; + accb_ctrl <= load_accb; + cc_ctrl <= load_cc; + + when "0100" => -- lsr + right_ctrl <= zero_right; + alu_ctrl <= alu_lsr8; + accb_ctrl <= load_accb; + cc_ctrl <= load_cc; + + when "0110" => -- ror + right_ctrl <= zero_right; + alu_ctrl <= alu_ror8; + accb_ctrl <= load_accb; + cc_ctrl <= load_cc; + + when "0111" => -- asr + right_ctrl <= zero_right; + alu_ctrl <= alu_asr8; + accb_ctrl <= load_accb; + cc_ctrl <= load_cc; + + when "1000" => -- asl + right_ctrl <= zero_right; + alu_ctrl <= alu_asl8; + accb_ctrl <= load_accb; + cc_ctrl <= load_cc; + + when "1001" => -- rol + right_ctrl <= zero_right; + alu_ctrl <= alu_rol8; + accb_ctrl <= load_accb; + cc_ctrl <= load_cc; + + when "1010" => -- dec + right_ctrl <= one_right; + alu_ctrl <= alu_dec; + accb_ctrl <= load_accb; + cc_ctrl <= load_cc; + + when "1011" => -- undefined + right_ctrl <= zero_right; + alu_ctrl <= alu_nop; + accb_ctrl <= latch_accb; + cc_ctrl <= latch_cc; + + when "1100" => -- inc + right_ctrl <= one_right; + alu_ctrl <= alu_inc; + accb_ctrl <= load_accb; + cc_ctrl <= load_cc; + + when "1101" => -- tst + right_ctrl <= zero_right; + alu_ctrl <= alu_st8; + accb_ctrl <= latch_accb; + cc_ctrl <= load_cc; + + when "1110" => -- jmp (undefined) + right_ctrl <= zero_right; + alu_ctrl <= alu_nop; + accb_ctrl <= latch_accb; + cc_ctrl <= latch_cc; + + when "1111" => -- clr + right_ctrl <= zero_right; + alu_ctrl <= alu_clr; + accb_ctrl <= load_accb; + cc_ctrl <= load_cc; + + when others => + right_ctrl <= zero_right; + alu_ctrl <= alu_nop; + accb_ctrl <= latch_accb; + cc_ctrl <= latch_cc; + end case; + lic <= '1'; + next_state <= fetch_state; + + -- + -- Single operand indexed + -- Two byte instruction so advance PC + -- EA should hold index offset + -- + when "0110" => -- indexed single op + -- increment the pc + pc_ctrl <= incr_pc; + st_ctrl <= push_st; + + case op_code(3 downto 0) is + when "1110" => -- jmp + return_state <= jmp_state; + + when "1111" => -- clr + return_state <= single_op_exec_state; + + when others => + return_state <= single_op_read_state; + + end case; + next_state <= indexed_state; + + -- + -- Single operand extended addressing + -- three byte instruction so advance the PC + -- Low order EA holds high order address + -- + when "0111" => -- extended single op + -- increment PC + pc_ctrl <= incr_pc; + st_ctrl <= push_st; + + case op_code(3 downto 0) is + when "1110" => -- jmp + return_state <= jmp_state; + + when "1111" => -- clr + return_state <= single_op_exec_state; + + when others => + return_state <= single_op_read_state; + + end case; + next_state <= extended_state; + + when "1000" => -- acca immediate + -- increment the pc + pc_ctrl <= incr_pc; + + case op_code(3 downto 0) is + when "0011" | -- subd #, cmpd #, cmpu # + "1100" | -- cmpx #, cmpy #, cmps # + "1110" => -- ldx #, ldy #, undef # + next_state <= imm16_state; + + -- + -- bsr offset - Branch to subroutine (2 bytes) + -- 6809 => 7 cycles + -- cpu09 => 5 cycles + -- 1 op=(pc) / pc=pc+1 + -- 2 md_hi=sign(pc) / md_lo=(pc) / sp=sp-1 / pc=pc+1 + -- 3 (sp)=pc_lo / sp=sp-1 + -- 4 (sp)=pc_hi + -- 5 pc=pc+md + -- + when "1101" => -- bsr + -- pre decrement SP + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- + st_ctrl <= push_st; + return_state <= sbranch_state; + next_state <= push_return_lo_state; + + when others => + lic <= '1'; + next_state <= fetch_state; + + end case; + + when "1001" => -- acca direct + -- increment the pc + pc_ctrl <= incr_pc; + case op_code(3 downto 0) is + when "0011" | -- subd <, cmpd <, cmpu < + "1100" | -- cmpx <, cmpy <, cmps < + "1110" => -- ldx <, ldy <, undef < + next_state <= dual_op_read16_state; + + when "0111" => -- sta direct + next_state <= dual_op_write8_state; + + -- + -- jsr direct - Jump to subroutine in direct page (2 bytes) + -- 6809 => 7 cycles + -- cpu09 => 5 cycles + -- 1 op=(pc) / pc=pc+1 + -- 2 ea_hi=0 / ea_lo=(pc) / sp=sp-1 / pc=pc+1 + -- 3 (sp)=pc_lo / sp=sp-1 + -- 4 (sp)=pc_hi + -- 5 pc=ea + -- + when "1101" => -- jsr direct + -- pre decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- + st_ctrl <= push_st; + return_state <= jmp_state; + next_state <= push_return_lo_state; + + + when "1111" => -- stx <, sty <, undef < + -- idle ALU + left_ctrl <= ix_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_nop; + cc_ctrl <= latch_cc; + sp_ctrl <= latch_sp; + next_state <= dual_op_write16_state; + + when others => + next_state <= dual_op_read8_state; + + end case; + + when "1010" => -- acca indexed + -- increment the pc + pc_ctrl <= incr_pc; + case op_code(3 downto 0) is + when "0011" | -- subd x, cmpd x, cmpu x + "1100" | -- cmpx x, cmpy x. cmps ,x + "1110" => -- ldx x, ldy x, undef x + st_ctrl <= push_st; + return_state <= dual_op_read16_state; + next_state <= indexed_state; + + when "0111" => -- staa ,x + st_ctrl <= push_st; + return_state <= dual_op_write8_state; + next_state <= indexed_state; + + when "1101" => -- jsr ,x + -- DO NOT pre decrement SP + st_ctrl <= push_st; + return_state <= jsr_state; + next_state <= indexed_state; + + when "1111" => -- stx ind, sty ind + st_ctrl <= push_st; + return_state <= dual_op_write16_state; + next_state <= indexed_state; + + when others => + st_ctrl <= push_st; + return_state <= dual_op_read8_state; + next_state <= indexed_state; + + end case; + + when "1011" => -- acca extended + -- increment the pc + pc_ctrl <= incr_pc; + case op_code(3 downto 0) is + when "0011" | -- subd >, cmpd >, cmpu > + "1100" | -- cmpx >, cmpy >, cmps > + "1110" => -- ldx > ldy >, undef > + st_ctrl <= push_st; + return_state <= dual_op_read16_state; + next_state <= extended_state; + + when "0111" => -- staa > + st_ctrl <= push_st; + return_state <= dual_op_write8_state; + next_state <= extended_state; + + when "1101" => -- jsr >extended + -- DO NOT pre decrement sp + st_ctrl <= push_st; + return_state <= jsr_state; + next_state <= extended_state; + + when "1111" => -- stx >, sty > + st_ctrl <= push_st; + return_state <= dual_op_write16_state; + next_state <= extended_state; + + when others => + st_ctrl <= push_st; + return_state <= dual_op_read8_state; + next_state <= extended_state; + + end case; + + when "1100" => -- accb immediate + -- increment the pc + pc_ctrl <= incr_pc; + case op_code(3 downto 0) is + when "0011" | -- addd #, undef #, undef # + "1100" | -- ldd #, undef #, undef # + "1110" => -- ldu #, lds #, undef # + next_state <= imm16_state; + + when others => + lic <= '1'; + next_state <= fetch_state; + + end case; + + when "1101" => -- accb direct + -- increment the pc + pc_ctrl <= incr_pc; + case op_code(3 downto 0) is + when "0011" | -- addd <, undef <, undef < + "1100" | -- ldd <, undef <, undef < + "1110" => -- ldu, lds <, undef < + next_state <= dual_op_read16_state; + + when "0111" => -- stab < + next_state <= dual_op_write8_state; + + when "1101" => -- std <, + next_state <= dual_op_write16_state; + + when "1111" => -- stu <, sts < + next_state <= dual_op_write16_state; + + when others => + next_state <= dual_op_read8_state; + + end case; + + when "1110" => -- accb indexed + -- increment the pc + pc_ctrl <= incr_pc; + case op_code(3 downto 0) is + when "0011" | -- addd x, undef x, undef x + "1100" | -- ldd x, undef x, undef x + "1110" => -- ldu x, lds x, undef x + st_ctrl <= push_st; + return_state <= dual_op_read16_state; + next_state <= indexed_state; + + when "0111" => -- stab x + st_ctrl <= push_st; + return_state <= dual_op_write8_state; + next_state <= indexed_state; + + when "1101" => -- std x + st_ctrl <= push_st; + return_state <= dual_op_write16_state; + next_state <= indexed_state; + + when "1111" => -- stu x, sts x, undef x + st_ctrl <= push_st; + return_state <= dual_op_write16_state; + next_state <= indexed_state; + + when others => + st_ctrl <= push_st; + return_state <= dual_op_read8_state; + next_state <= indexed_state; + + end case; + + when "1111" => -- accb extended + -- increment the pc + pc_ctrl <= incr_pc; + case op_code(3 downto 0) is + when "0011" | -- addd >, undef >, undef > + "1100" | -- ldd >, undef >, undef > + "1110" => -- ldu >, lds >, undef > + st_ctrl <= push_st; + return_state <= dual_op_read16_state; + next_state <= extended_state; + + when "0111" => -- stab extended + st_ctrl <= push_st; + return_state <= dual_op_write8_state; + next_state <= extended_state; + + when "1101" => -- std extended + st_ctrl <= push_st; + return_state <= dual_op_write16_state; + next_state <= extended_state; + + when "1111" => -- stu extended + st_ctrl <= push_st; + return_state <= dual_op_write16_state; + next_state <= extended_state; + + when others => + st_ctrl <= push_st; + return_state <= dual_op_read8_state; + next_state <= extended_state; + end case; + -- + -- not sure why I need this + -- + when others => + lic <= '1'; + next_state <= fetch_state; + end case; + + + -- + -- here if ea holds low byte + -- Direct + -- Extended + -- Indexed + -- read memory location + -- + when single_op_read_state => + -- read memory into md + md_ctrl <= fetch_first_md; + addr_ctrl <= read_ad; + dout_ctrl <= md_lo_dout; + next_state <= single_op_exec_state; + + when single_op_exec_state => + case op_code(3 downto 0) is + when "0000" => -- neg + left_ctrl <= md_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_neg; + cc_ctrl <= load_cc; + md_ctrl <= load_md; + next_state <= single_op_write_state; + when "0011" => -- com + left_ctrl <= md_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_com; + cc_ctrl <= load_cc; + md_ctrl <= load_md; + next_state <= single_op_write_state; + when "0100" => -- lsr + left_ctrl <= md_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_lsr8; + cc_ctrl <= load_cc; + md_ctrl <= load_md; + next_state <= single_op_write_state; + when "0110" => -- ror + left_ctrl <= md_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_ror8; + cc_ctrl <= load_cc; + md_ctrl <= load_md; + next_state <= single_op_write_state; + when "0111" => -- asr + left_ctrl <= md_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_asr8; + cc_ctrl <= load_cc; + md_ctrl <= load_md; + next_state <= single_op_write_state; + when "1000" => -- asl + left_ctrl <= md_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_asl8; + cc_ctrl <= load_cc; + md_ctrl <= load_md; + next_state <= single_op_write_state; + when "1001" => -- rol + left_ctrl <= md_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_rol8; + cc_ctrl <= load_cc; + md_ctrl <= load_md; + next_state <= single_op_write_state; + when "1010" => -- dec + left_ctrl <= md_left; + right_ctrl <= one_right; + alu_ctrl <= alu_dec; + cc_ctrl <= load_cc; + md_ctrl <= load_md; + next_state <= single_op_write_state; + when "1011" => -- undefined + lic <= '1'; + next_state <= fetch_state; + when "1100" => -- inc + left_ctrl <= md_left; + right_ctrl <= one_right; + alu_ctrl <= alu_inc; + cc_ctrl <= load_cc; + md_ctrl <= load_md; + next_state <= single_op_write_state; + when "1101" => -- tst + left_ctrl <= md_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_st8; + cc_ctrl <= load_cc; + lic <= '1'; + next_state <= fetch_state; + when "1110" => -- jmp + left_ctrl <= md_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_ld16; + pc_ctrl <= load_pc; + lic <= '1'; + next_state <= fetch_state; + when "1111" => -- clr + left_ctrl <= md_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_clr; + cc_ctrl <= load_cc; + md_ctrl <= load_md; + next_state <= single_op_write_state; + when others => + lic <= '1'; + next_state <= fetch_state; + end case; + -- + -- single operand 8 bit write + -- Write low 8 bits of ALU output + -- EA holds address + -- MD holds data + -- + when single_op_write_state => + -- write ALU low byte output + addr_ctrl <= write_ad; + dout_ctrl <= md_lo_dout; + lic <= '1'; + next_state <= fetch_state; + + -- + -- here if ea holds address of low byte + -- read memory location + -- + when dual_op_read8_state => + -- read first data byte from ea + md_ctrl <= fetch_first_md; + addr_ctrl <= read_ad; + lic <= '1'; + next_state <= fetch_state; + + -- + -- Here to read a 16 bit value into MD + -- pointed to by the EA register + -- The first byte is read + -- and the EA is incremented + -- + when dual_op_read16_state => + -- increment the effective address + left_ctrl <= ea_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + -- read the high byte of the 16 bit data + md_ctrl <= fetch_first_md; + addr_ctrl <= read_ad; + next_state <= dual_op_read16_2_state; + + -- + -- here to read the second byte + -- pointed to by EA into MD + -- + when dual_op_read16_2_state => + -- read the low byte of the 16 bit data + md_ctrl <= fetch_next_md; + addr_ctrl <= read_ad; + lic <= '1'; + next_state <= fetch_state; + + -- + -- 16 bit Write state + -- EA hold address of memory to write to + -- Advance the effective address in ALU + -- decode op_code to determine which + -- register to write + -- + when dual_op_write16_state => + -- increment the effective address + left_ctrl <= ea_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + -- write the ALU hi byte at ea + addr_ctrl <= write_ad; + if op_code(6) = '0' then + case op_code(3 downto 0) is + when "1111" => -- stx / sty + case pre_code is + when "00010000" => -- page 2 -- sty + dout_ctrl <= iy_hi_dout; + when others => -- page 1 -- stx + dout_ctrl <= ix_hi_dout; + end case; + when others => + dout_ctrl <= md_hi_dout; + end case; + else + case op_code(3 downto 0) is + when "1101" => -- std + dout_ctrl <= acca_dout; -- acca is high byte of ACCD + when "1111" => -- stu / sts + case pre_code is + when "00010000" => -- page 2 -- sts + dout_ctrl <= sp_hi_dout; + when others => -- page 1 -- stu + dout_ctrl <= up_hi_dout; + end case; + when others => + dout_ctrl <= md_hi_dout; + end case; + end if; + next_state <= dual_op_write8_state; + + -- + -- Dual operand 8 bit write + -- Write 8 bit accumulator + -- or low byte of 16 bit register + -- EA holds address + -- decode opcode to determine + -- which register to apply to the bus + -- Also set the condition codes here + -- + when dual_op_write8_state => + if op_code(6) = '0' then + case op_code(3 downto 0) is + when "0111" => -- sta + dout_ctrl <= acca_dout; + when "1111" => -- stx / sty + case pre_code is + when "00010000" => -- page 2 -- sty + dout_ctrl <= iy_lo_dout; + when others => -- page 1 -- stx + dout_ctrl <= ix_lo_dout; + end case; + when others => + dout_ctrl <= md_lo_dout; + end case; + else + case op_code(3 downto 0) is + when "0111" => -- stb + dout_ctrl <= accb_dout; + when "1101" => -- std + dout_ctrl <= accb_dout; -- accb is low byte of accd + when "1111" => -- stu / sts + case pre_code is + when "00010000" => -- page 2 -- sts + dout_ctrl <= sp_lo_dout; + when others => -- page 1 -- stu + dout_ctrl <= up_lo_dout; + end case; + when others => + dout_ctrl <= md_lo_dout; + end case; + end if; + -- write ALU low byte output + addr_ctrl <= write_ad; + lic <= '1'; + next_state <= fetch_state; + + -- + -- 16 bit immediate addressing mode + -- + when imm16_state => + -- increment pc + pc_ctrl <= incr_pc; + -- fetch next immediate byte + md_ctrl <= fetch_next_md; + addr_ctrl <= fetch_ad; + lic <= '1'; + next_state <= fetch_state; + + -- + -- md & ea holds 8 bit index offset + -- calculate the effective memory address + -- using the alu + -- + when indexed_state => + -- + -- decode indexing mode + -- + if md(7) = '0' then + case md(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + when "01" => + left_ctrl <= iy_left; + when "10" => + left_ctrl <= up_left; + when others => + -- when "11" => + left_ctrl <= sp_left; + end case; + right_ctrl <= md_sign5_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + next_state <= saved_state; + + else + case md(3 downto 0) is + when "0000" => -- ,R+ + case md(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + when "01" => + left_ctrl <= iy_left; + when "10" => + left_ctrl <= up_left; + when others => + left_ctrl <= sp_left; + end case; + -- + right_ctrl <= zero_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + next_state <= postincr1_state; + + when "0001" => -- ,R++ + case md(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + when "01" => + left_ctrl <= iy_left; + when "10" => + left_ctrl <= up_left; + when others => + -- when "11" => + left_ctrl <= sp_left; + end case; + right_ctrl <= zero_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + next_state <= postincr2_state; + + when "0010" => -- ,-R + case md(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + ix_ctrl <= load_ix; + when "01" => + left_ctrl <= iy_left; + iy_ctrl <= load_iy; + when "10" => + left_ctrl <= up_left; + up_ctrl <= load_up; + when others => + -- when "11" => + left_ctrl <= sp_left; + sp_ctrl <= load_sp; + end case; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + ea_ctrl <= load_ea; + next_state <= saved_state; + + when "0011" => -- ,--R + case md(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + ix_ctrl <= load_ix; + when "01" => + left_ctrl <= iy_left; + iy_ctrl <= load_iy; + when "10" => + left_ctrl <= up_left; + up_ctrl <= load_up; + when others => + -- when "11" => + left_ctrl <= sp_left; + sp_ctrl <= load_sp; + end case; + right_ctrl <= two_right; + alu_ctrl <= alu_sub16; + ea_ctrl <= load_ea; + if md(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + + when "0100" => -- ,R (zero offset) + case md(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + when "01" => + left_ctrl <= iy_left; + when "10" => + left_ctrl <= up_left; + when others => + -- when "11" => + left_ctrl <= sp_left; + end case; + right_ctrl <= zero_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + if md(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + + when "0101" => -- ACCB,R + case md(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + when "01" => + left_ctrl <= iy_left; + when "10" => + left_ctrl <= up_left; + when others => + -- when "11" => + left_ctrl <= sp_left; + end case; + right_ctrl <= accb_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + if md(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + + when "0110" => -- ACCA,R + case md(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + when "01" => + left_ctrl <= iy_left; + when "10" => + left_ctrl <= up_left; + when others => + -- when "11" => + left_ctrl <= sp_left; + end case; + right_ctrl <= acca_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + if md(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + + when "0111" => -- undefined + case md(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + when "01" => + left_ctrl <= iy_left; + when "10" => + left_ctrl <= up_left; + when others => + -- when "11" => + left_ctrl <= sp_left; + end case; + right_ctrl <= zero_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + if md(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + + when "1000" => -- offset8,R + md_ctrl <= fetch_first_md; -- pick up 8 bit offset + addr_ctrl <= fetch_ad; + pc_ctrl <= incr_pc; + next_state <= index8_state; + + when "1001" => -- offset16,R + md_ctrl <= fetch_first_md; -- pick up first byte of 16 bit offset + addr_ctrl <= fetch_ad; + pc_ctrl <= incr_pc; + next_state <= index16_state; + + when "1010" => -- undefined + case md(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + when "01" => + left_ctrl <= iy_left; + when "10" => + left_ctrl <= up_left; + when others => + -- when "11" => + left_ctrl <= sp_left; + end case; + right_ctrl <= zero_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + -- + if md(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + + when "1011" => -- ACCD,R + case md(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + when "01" => + left_ctrl <= iy_left; + when "10" => + left_ctrl <= up_left; + when others => + -- when "11" => + left_ctrl <= sp_left; + end case; + right_ctrl <= accd_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + if md(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + + when "1100" => -- offset8,PC + -- fetch 8 bit offset + md_ctrl <= fetch_first_md; + addr_ctrl <= fetch_ad; + pc_ctrl <= incr_pc; + next_state <= pcrel8_state; + + when "1101" => -- offset16,PC + -- fetch offset + md_ctrl <= fetch_first_md; + addr_ctrl <= fetch_ad; + pc_ctrl <= incr_pc; + next_state <= pcrel16_state; + + when "1110" => -- undefined + case md(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + when "01" => + left_ctrl <= iy_left; + when "10" => + left_ctrl <= up_left; + when others => + -- when "11" => + left_ctrl <= sp_left; + end case; + right_ctrl <= zero_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + if md(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + + when others => +-- when "1111" => -- [,address] + -- advance PC to pick up address + md_ctrl <= fetch_first_md; + addr_ctrl <= fetch_ad; + pc_ctrl <= incr_pc; + next_state <= indexaddr_state; + end case; + end if; + + -- load index register with ea plus one + when postincr1_state => + left_ctrl <= ea_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + case md(6 downto 5) is + when "00" => + ix_ctrl <= load_ix; + when "01" => + iy_ctrl <= load_iy; + when "10" => + up_ctrl <= load_up; + when others => + -- when "11" => + sp_ctrl <= load_sp; + end case; + -- return to previous state + if md(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + + -- load index register with ea plus two + when postincr2_state => + -- increment register by two (address) + left_ctrl <= ea_left; + right_ctrl <= two_right; + alu_ctrl <= alu_add16; + case md(6 downto 5) is + when "00" => + ix_ctrl <= load_ix; + when "01" => + iy_ctrl <= load_iy; + when "10" => + up_ctrl <= load_up; + when others => + -- when "11" => + sp_ctrl <= load_sp; + end case; + -- return to previous state + if md(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + -- + -- ea = index register + md (8 bit signed offset) + -- ea holds post byte + -- + when index8_state => + case ea(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + when "01" => + left_ctrl <= iy_left; + when "10" => + left_ctrl <= up_left; + when others => + -- when "11" => + left_ctrl <= sp_left; + end case; + -- ea = index reg + md + right_ctrl <= md_sign8_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + -- return to previous state + if ea(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + + -- fetch low byte of 16 bit indexed offset + when index16_state => + -- advance pc + pc_ctrl <= incr_pc; + -- fetch low byte + md_ctrl <= fetch_next_md; + addr_ctrl <= fetch_ad; + next_state <= index16_2_state; + + -- ea = index register + md (16 bit offset) + -- ea holds post byte + when index16_2_state => + case ea(6 downto 5) is + when "00" => + left_ctrl <= ix_left; + when "01" => + left_ctrl <= iy_left; + when "10" => + left_ctrl <= up_left; + when others => + -- when "11" => + left_ctrl <= sp_left; + end case; + -- ea = index reg + md + right_ctrl <= md_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + -- return to previous state + if ea(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + -- + -- pc relative with 8 bit signed offest + -- md holds signed offset + -- + when pcrel8_state => + -- ea = pc + signed md + left_ctrl <= pc_left; + right_ctrl <= md_sign8_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + -- return to previous state + if ea(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + + -- pc relative addressing with 16 bit offset + -- pick up the low byte of the offset in md + -- advance the pc + when pcrel16_state => + -- advance pc + pc_ctrl <= incr_pc; + -- fetch low byte + md_ctrl <= fetch_next_md; + addr_ctrl <= fetch_ad; + next_state <= pcrel16_2_state; + + -- pc relative with16 bit signed offest + -- md holds signed offset + when pcrel16_2_state => + -- ea = pc + md + left_ctrl <= pc_left; + right_ctrl <= md_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + -- return to previous state + if ea(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + + -- indexed to address + -- pick up the low byte of the address + -- advance the pc + when indexaddr_state => + -- advance pc + pc_ctrl <= incr_pc; + -- fetch low byte + md_ctrl <= fetch_next_md; + addr_ctrl <= fetch_ad; + next_state <= indexaddr2_state; + + -- indexed to absolute address + -- md holds address + -- ea hold indexing mode byte + when indexaddr2_state => + -- ea = md + left_ctrl <= pc_left; + right_ctrl <= md_right; + alu_ctrl <= alu_ld16; + ea_ctrl <= load_ea; + -- return to previous state + if ea(4) = '0' then + next_state <= saved_state; + else + next_state <= indirect_state; + end if; + + -- + -- load md with high byte of indirect address + -- pointed to by ea + -- increment ea + -- + when indirect_state => + -- increment ea + left_ctrl <= ea_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + ea_ctrl <= load_ea; + -- fetch high byte + md_ctrl <= fetch_first_md; + addr_ctrl <= read_ad; + next_state <= indirect2_state; + -- + -- load md with low byte of indirect address + -- pointed to by ea + -- ea has previously been incremented + -- + when indirect2_state => + -- fetch high byte + md_ctrl <= fetch_next_md; + addr_ctrl <= read_ad; + dout_ctrl <= md_lo_dout; + next_state <= indirect3_state; + -- + -- complete idirect addressing + -- by loading ea with md + -- + when indirect3_state => + -- load ea with md + left_ctrl <= ea_left; + right_ctrl <= md_right; + alu_ctrl <= alu_ld16; + ea_ctrl <= load_ea; + -- return to previous state + next_state <= saved_state; + + -- + -- ea holds the low byte of the absolute address + -- Move ea low byte into ea high byte + -- load new ea low byte to for absolute 16 bit address + -- advance the program counter + -- + when extended_state => -- fetch ea low byte + -- increment pc + pc_ctrl <= incr_pc; + -- fetch next effective address bytes + ea_ctrl <= fetch_next_ea; + addr_ctrl <= fetch_ad; + -- return to previous state + next_state <= saved_state; + + when lea_state => -- here on load effective address + -- load index register with effective address + left_ctrl <= pc_left; + right_ctrl <= ea_right; + alu_ctrl <= alu_lea; + case op_code(3 downto 0) is + when "0000" => -- leax + cc_ctrl <= load_cc; + ix_ctrl <= load_ix; + when "0001" => -- leay + cc_ctrl <= load_cc; + iy_ctrl <= load_iy; + when "0010" => -- leas + sp_ctrl <= load_sp; + when "0011" => -- leau + up_ctrl <= load_up; + when others => + null; + end case; + lic <= '1'; + next_state <= fetch_state; + + -- + -- jump to subroutine + -- sp=sp-1 + -- call push_return_lo_state to save pc + -- return to jmp_state + -- + when jsr_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- call push_return_state + st_ctrl <= push_st; + return_state <= jmp_state; + next_state <= push_return_lo_state; + + -- + -- Load pc with ea + -- (JMP) + -- + when jmp_state => + -- load PC with effective address + left_ctrl <= pc_left; + right_ctrl <= ea_right; + alu_ctrl <= alu_ld16; + pc_ctrl <= load_pc; + lic <= '1'; + next_state <= fetch_state; + + -- + -- long branch or branch to subroutine + -- pick up next md byte + -- md_hi = md_lo + -- md_lo = (pc) + -- pc=pc+1 + -- if a lbsr push return address + -- continue to sbranch_state + -- to evaluate conditional branches + -- + when lbranch_state => + pc_ctrl <= incr_pc; + -- fetch the next byte into md_lo + md_ctrl <= fetch_next_md; + addr_ctrl <= fetch_ad; + -- if lbsr - push return address + -- then continue on to short branch + if op_code = "00010111" then + st_ctrl <= push_st; + return_state <= sbranch_state; + next_state <= push_return_lo_state; + else + next_state <= sbranch_state; + end if; + + -- + -- here to execute conditional branch + -- short conditional branch md = signed 8 bit offset + -- long branch md = 16 bit offset + -- + when sbranch_state => + left_ctrl <= pc_left; + right_ctrl <= md_right; + alu_ctrl <= alu_add16; + -- Test condition for branch + if op_code(7 downto 4) = "0010" then -- conditional branch + case op_code(3 downto 0) is + when "0000" => -- bra + cond_true := (1 = 1); + when "0001" => -- brn + cond_true := (1 = 0); + when "0010" => -- bhi + cond_true := ((cc(CBIT) or cc(ZBIT)) = '0'); + when "0011" => -- bls + cond_true := ((cc(CBIT) or cc(ZBIT)) = '1'); + when "0100" => -- bcc/bhs + cond_true := (cc(CBIT) = '0'); + when "0101" => -- bcs/blo + cond_true := (cc(CBIT) = '1'); + when "0110" => -- bne + cond_true := (cc(ZBIT) = '0'); + when "0111" => -- beq + cond_true := (cc(ZBIT) = '1'); + when "1000" => -- bvc + cond_true := (cc(VBIT) = '0'); + when "1001" => -- bvs + cond_true := (cc(VBIT) = '1'); + when "1010" => -- bpl + cond_true := (cc(NBIT) = '0'); + when "1011" => -- bmi + cond_true := (cc(NBIT) = '1'); + when "1100" => -- bge + cond_true := ((cc(NBIT) xor cc(VBIT)) = '0'); + when "1101" => -- blt + cond_true := ((cc(NBIT) xor cc(VBIT)) = '1'); + when "1110" => -- bgt + cond_true := ((cc(ZBIT) or (cc(NBIT) xor cc(VBIT))) = '0'); + when "1111" => -- ble + cond_true := ((cc(ZBIT) or (cc(NBIT) xor cc(VBIT))) = '1'); + when others => + null; + end case; + end if; + if cond_true then + pc_ctrl <= load_pc; + end if; + lic <= '1'; + next_state <= fetch_state; + + -- + -- push return address onto the S stack + -- + -- (sp) = pc_lo + -- sp = sp - 1 + -- + when push_return_lo_state => + -- decrement the sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write PC low + addr_ctrl <= pushs_ad; + dout_ctrl <= pc_lo_dout; + next_state <= push_return_hi_state; + + -- + -- push program counter hi byte onto the stack + -- (sp) = pc_hi + -- sp = sp + -- return to originating state + -- + when push_return_hi_state => + -- write pc hi bytes + addr_ctrl <= pushs_ad; + dout_ctrl <= pc_hi_dout; + next_state <= saved_state; + + -- + -- RTS pull return address from stack + -- + when pull_return_hi_state => + -- increment the sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read pc hi + pc_ctrl <= pull_hi_pc; + addr_ctrl <= pulls_ad; + next_state <= pull_return_lo_state; + + when pull_return_lo_state => + -- increment the SP + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read pc low + pc_ctrl <= pull_lo_pc; + addr_ctrl <= pulls_ad; + dout_ctrl <= pc_lo_dout; + -- + lic <= '1'; + next_state <= fetch_state; + + when andcc_state => + -- AND CC with md + left_ctrl <= md_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_andcc; + cc_ctrl <= load_cc; + -- + lic <= '1'; + next_state <= fetch_state; + + when orcc_state => + -- OR CC with md + left_ctrl <= md_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_orcc; + cc_ctrl <= load_cc; + -- + lic <= '1'; + next_state <= fetch_state; + + when tfr_state => + -- select source register + case md(7 downto 4) is + when "0000" => + left_ctrl <= accd_left; + when "0001" => + left_ctrl <= ix_left; + when "0010" => + left_ctrl <= iy_left; + when "0011" => + left_ctrl <= up_left; + when "0100" => + left_ctrl <= sp_left; + when "0101" => + left_ctrl <= pc_left; + when "1000" => + left_ctrl <= acca_left; + when "1001" => + left_ctrl <= accb_left; + when "1010" => + left_ctrl <= cc_left; + when "1011" => + left_ctrl <= dp_left; + when others => + left_ctrl <= md_left; + end case; + right_ctrl <= zero_right; + alu_ctrl <= alu_tfr; + -- select destination register + case md(3 downto 0) is + when "0000" => -- accd + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + when "0001" => -- ix + ix_ctrl <= load_ix; + when "0010" => -- iy + iy_ctrl <= load_iy; + when "0011" => -- up + up_ctrl <= load_up; + when "0100" => -- sp + sp_ctrl <= load_sp; + when "0101" => -- pc + pc_ctrl <= load_pc; + when "1000" => -- acca + acca_ctrl <= load_acca; + when "1001" => -- accb + accb_ctrl <= load_accb; + when "1010" => -- cc + cc_ctrl <= load_cc; + when "1011" => --dp + dp_ctrl <= load_dp; + when others => + null; + end case; + -- + lic <= '1'; + next_state <= fetch_state; + + when exg_state => + -- save destination register + case md(3 downto 0) is + when "0000" => + left_ctrl <= accd_left; + when "0001" => + left_ctrl <= ix_left; + when "0010" => + left_ctrl <= iy_left; + when "0011" => + left_ctrl <= up_left; + when "0100" => + left_ctrl <= sp_left; + when "0101" => + left_ctrl <= pc_left; + when "1000" => + left_ctrl <= acca_left; + when "1001" => + left_ctrl <= accb_left; + when "1010" => + left_ctrl <= cc_left; + when "1011" => + left_ctrl <= dp_left; + when others => + left_ctrl <= md_left; + end case; + right_ctrl <= zero_right; + alu_ctrl <= alu_tfr; + ea_ctrl <= load_ea; + -- call tranfer microcode + next_state <= exg1_state; + + when exg1_state => + -- select source register + case md(7 downto 4) is + when "0000" => + left_ctrl <= accd_left; + when "0001" => + left_ctrl <= ix_left; + when "0010" => + left_ctrl <= iy_left; + when "0011" => + left_ctrl <= up_left; + when "0100" => + left_ctrl <= sp_left; + when "0101" => + left_ctrl <= pc_left; + when "1000" => + left_ctrl <= acca_left; + when "1001" => + left_ctrl <= accb_left; + when "1010" => + left_ctrl <= cc_left; + when "1011" => + left_ctrl <= dp_left; + when others => + left_ctrl <= md_left; + end case; + right_ctrl <= zero_right; + alu_ctrl <= alu_tfr; + -- select destination register + case md(3 downto 0) is + when "0000" => -- accd + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + when "0001" => -- ix + ix_ctrl <= load_ix; + when "0010" => -- iy + iy_ctrl <= load_iy; + when "0011" => -- up + up_ctrl <= load_up; + when "0100" => -- sp + sp_ctrl <= load_sp; + when "0101" => -- pc + pc_ctrl <= load_pc; + when "1000" => -- acca + acca_ctrl <= load_acca; + when "1001" => -- accb + accb_ctrl <= load_accb; + when "1010" => -- cc + cc_ctrl <= load_cc; + when "1011" => --dp + dp_ctrl <= load_dp; + when others => + null; + end case; + next_state <= exg2_state; + + when exg2_state => + -- restore destination + left_ctrl <= ea_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_tfr; + -- save as source register + case md(7 downto 4) is + when "0000" => -- accd + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + when "0001" => -- ix + ix_ctrl <= load_ix; + when "0010" => -- iy + iy_ctrl <= load_iy; + when "0011" => -- up + up_ctrl <= load_up; + when "0100" => -- sp + sp_ctrl <= load_sp; + when "0101" => -- pc + pc_ctrl <= load_pc; + when "1000" => -- acca + acca_ctrl <= load_acca; + when "1001" => -- accb + accb_ctrl <= load_accb; + when "1010" => -- cc + cc_ctrl <= load_cc; + when "1011" => --dp + dp_ctrl <= load_dp; + when others => + null; + end case; + lic <= '1'; + next_state <= fetch_state; + + when mulea_state => + -- move accb to ea + left_ctrl <= accb_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_st16; + ea_ctrl <= load_ea; + next_state <= muld_state; + + when muld_state => + -- clear accd + left_ctrl <= acca_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_ld8; + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + next_state <= mul0_state; + + when mul0_state => + -- if bit 0 of ea set, add accd to md + left_ctrl <= accd_left; + if ea(0) = '1' then + right_ctrl <= md_right; + else + right_ctrl <= zero_right; + end if; + alu_ctrl <= alu_mul; + cc_ctrl <= load_cc; + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + md_ctrl <= shiftl_md; + next_state <= mul1_state; + + when mul1_state => + -- if bit 1 of ea set, add accd to md + left_ctrl <= accd_left; + if ea(1) = '1' then + right_ctrl <= md_right; + else + right_ctrl <= zero_right; + end if; + alu_ctrl <= alu_mul; + cc_ctrl <= load_cc; + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + md_ctrl <= shiftl_md; + next_state <= mul2_state; + + when mul2_state => + -- if bit 2 of ea set, add accd to md + left_ctrl <= accd_left; + if ea(2) = '1' then + right_ctrl <= md_right; + else + right_ctrl <= zero_right; + end if; + alu_ctrl <= alu_mul; + cc_ctrl <= load_cc; + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + md_ctrl <= shiftl_md; + next_state <= mul3_state; + + when mul3_state => + -- if bit 3 of ea set, add accd to md + left_ctrl <= accd_left; + if ea(3) = '1' then + right_ctrl <= md_right; + else + right_ctrl <= zero_right; + end if; + alu_ctrl <= alu_mul; + cc_ctrl <= load_cc; + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + md_ctrl <= shiftl_md; + next_state <= mul4_state; + + when mul4_state => + -- if bit 4 of ea set, add accd to md + left_ctrl <= accd_left; + if ea(4) = '1' then + right_ctrl <= md_right; + else + right_ctrl <= zero_right; + end if; + alu_ctrl <= alu_mul; + cc_ctrl <= load_cc; + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + md_ctrl <= shiftl_md; + next_state <= mul5_state; + + when mul5_state => + -- if bit 5 of ea set, add accd to md + left_ctrl <= accd_left; + if ea(5) = '1' then + right_ctrl <= md_right; + else + right_ctrl <= zero_right; + end if; + alu_ctrl <= alu_mul; + cc_ctrl <= load_cc; + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + md_ctrl <= shiftl_md; + next_state <= mul6_state; + + when mul6_state => + -- if bit 6 of ea set, add accd to md + left_ctrl <= accd_left; + if ea(6) = '1' then + right_ctrl <= md_right; + else + right_ctrl <= zero_right; + end if; + alu_ctrl <= alu_mul; + cc_ctrl <= load_cc; + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + md_ctrl <= shiftl_md; + lic <= '1'; + next_state <= fetch_state; + + -- + -- Enter here on pushs + -- ea holds post byte + -- + when pshs_state => + -- decrement sp if any registers to be pushed + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + -- idle address + addr_ctrl <= idle_ad; + dout_ctrl <= cc_dout; + if ea(7 downto 0) = "00000000" then + sp_ctrl <= latch_sp; + else + sp_ctrl <= load_sp; + end if; + if ea(7) = '1' then + next_state <= pshs_pcl_state; + elsif ea(6) = '1' then + next_state <= pshs_upl_state; + elsif ea(5) = '1' then + next_state <= pshs_iyl_state; + elsif ea(4) = '1' then + next_state <= pshs_ixl_state; + elsif ea(3) = '1' then + next_state <= pshs_dp_state; + elsif ea(2) = '1' then + next_state <= pshs_accb_state; + elsif ea(1) = '1' then + next_state <= pshs_acca_state; + elsif ea(0) = '1' then + next_state <= pshs_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshs_pcl_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write pc low + addr_ctrl <= pushs_ad; + dout_ctrl <= pc_lo_dout; + next_state <= pshs_pch_state; + + when pshs_pch_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(6 downto 0) = "0000000" then + sp_ctrl <= latch_sp; + else + sp_ctrl <= load_sp; + end if; + -- write pc hi + addr_ctrl <= pushs_ad; + dout_ctrl <= pc_hi_dout; + if ea(6) = '1' then + next_state <= pshs_upl_state; + elsif ea(5) = '1' then + next_state <= pshs_iyl_state; + elsif ea(4) = '1' then + next_state <= pshs_ixl_state; + elsif ea(3) = '1' then + next_state <= pshs_dp_state; + elsif ea(2) = '1' then + next_state <= pshs_accb_state; + elsif ea(1) = '1' then + next_state <= pshs_acca_state; + elsif ea(0) = '1' then + next_state <= pshs_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + + when pshs_upl_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write pc low + addr_ctrl <= pushs_ad; + dout_ctrl <= up_lo_dout; + next_state <= pshs_uph_state; + + when pshs_uph_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(5 downto 0) = "000000" then + sp_ctrl <= latch_sp; + else + sp_ctrl <= load_sp; + end if; + -- write pc hi + addr_ctrl <= pushs_ad; + dout_ctrl <= up_hi_dout; + if ea(5) = '1' then + next_state <= pshs_iyl_state; + elsif ea(4) = '1' then + next_state <= pshs_ixl_state; + elsif ea(3) = '1' then + next_state <= pshs_dp_state; + elsif ea(2) = '1' then + next_state <= pshs_accb_state; + elsif ea(1) = '1' then + next_state <= pshs_acca_state; + elsif ea(0) = '1' then + next_state <= pshs_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshs_iyl_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write iy low + addr_ctrl <= pushs_ad; + dout_ctrl <= iy_lo_dout; + next_state <= pshs_iyh_state; + + when pshs_iyh_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(4 downto 0) = "00000" then + sp_ctrl <= latch_sp; + else + sp_ctrl <= load_sp; + end if; + -- write iy hi + addr_ctrl <= pushs_ad; + dout_ctrl <= iy_hi_dout; + if ea(4) = '1' then + next_state <= pshs_ixl_state; + elsif ea(3) = '1' then + next_state <= pshs_dp_state; + elsif ea(2) = '1' then + next_state <= pshs_accb_state; + elsif ea(1) = '1' then + next_state <= pshs_acca_state; + elsif ea(0) = '1' then + next_state <= pshs_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshs_ixl_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write ix low + addr_ctrl <= pushs_ad; + dout_ctrl <= ix_lo_dout; + next_state <= pshs_ixh_state; + + when pshs_ixh_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(3 downto 0) = "0000" then + sp_ctrl <= latch_sp; + else + sp_ctrl <= load_sp; + end if; + -- write ix hi + addr_ctrl <= pushs_ad; + dout_ctrl <= ix_hi_dout; + if ea(3) = '1' then + next_state <= pshs_dp_state; + elsif ea(2) = '1' then + next_state <= pshs_accb_state; + elsif ea(1) = '1' then + next_state <= pshs_acca_state; + elsif ea(0) = '1' then + next_state <= pshs_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshs_dp_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(2 downto 0) = "000" then + sp_ctrl <= latch_sp; + else + sp_ctrl <= load_sp; + end if; + -- write dp + addr_ctrl <= pushs_ad; + dout_ctrl <= dp_dout; + if ea(2) = '1' then + next_state <= pshs_accb_state; + elsif ea(1) = '1' then + next_state <= pshs_acca_state; + elsif ea(0) = '1' then + next_state <= pshs_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshs_accb_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(1 downto 0) = "00" then + sp_ctrl <= latch_sp; + else + sp_ctrl <= load_sp; + end if; + -- write accb + addr_ctrl <= pushs_ad; + dout_ctrl <= accb_dout; + if ea(1) = '1' then + next_state <= pshs_acca_state; + elsif ea(0) = '1' then + next_state <= pshs_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshs_acca_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(0) = '1' then + sp_ctrl <= load_sp; + else + sp_ctrl <= latch_sp; + end if; + -- write acca + addr_ctrl <= pushs_ad; + dout_ctrl <= acca_dout; + if ea(0) = '1' then + next_state <= pshs_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshs_cc_state => + -- idle sp + -- write cc + addr_ctrl <= pushs_ad; + dout_ctrl <= cc_dout; + lic <= '1'; + next_state <= fetch_state; + + -- + -- enter here on PULS + -- ea hold register mask + -- + when puls_state => + if ea(0) = '1' then + next_state <= puls_cc_state; + elsif ea(1) = '1' then + next_state <= puls_acca_state; + elsif ea(2) = '1' then + next_state <= puls_accb_state; + elsif ea(3) = '1' then + next_state <= puls_dp_state; + elsif ea(4) = '1' then + next_state <= puls_ixh_state; + elsif ea(5) = '1' then + next_state <= puls_iyh_state; + elsif ea(6) = '1' then + next_state <= puls_uph_state; + elsif ea(7) = '1' then + next_state <= puls_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when puls_cc_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read cc + cc_ctrl <= pull_cc; + addr_ctrl <= pulls_ad; + if ea(1) = '1' then + next_state <= puls_acca_state; + elsif ea(2) = '1' then + next_state <= puls_accb_state; + elsif ea(3) = '1' then + next_state <= puls_dp_state; + elsif ea(4) = '1' then + next_state <= puls_ixh_state; + elsif ea(5) = '1' then + next_state <= puls_iyh_state; + elsif ea(6) = '1' then + next_state <= puls_uph_state; + elsif ea(7) = '1' then + next_state <= puls_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when puls_acca_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read acca + acca_ctrl <= pull_acca; + addr_ctrl <= pulls_ad; + if ea(2) = '1' then + next_state <= puls_accb_state; + elsif ea(3) = '1' then + next_state <= puls_dp_state; + elsif ea(4) = '1' then + next_state <= puls_ixh_state; + elsif ea(5) = '1' then + next_state <= puls_iyh_state; + elsif ea(6) = '1' then + next_state <= puls_uph_state; + elsif ea(7) = '1' then + next_state <= puls_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when puls_accb_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read accb + accb_ctrl <= pull_accb; + addr_ctrl <= pulls_ad; + if ea(3) = '1' then + next_state <= puls_dp_state; + elsif ea(4) = '1' then + next_state <= puls_ixh_state; + elsif ea(5) = '1' then + next_state <= puls_iyh_state; + elsif ea(6) = '1' then + next_state <= puls_uph_state; + elsif ea(7) = '1' then + next_state <= puls_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when puls_dp_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read dp + dp_ctrl <= pull_dp; + addr_ctrl <= pulls_ad; + if ea(4) = '1' then + next_state <= puls_ixh_state; + elsif ea(5) = '1' then + next_state <= puls_iyh_state; + elsif ea(6) = '1' then + next_state <= puls_uph_state; + elsif ea(7) = '1' then + next_state <= puls_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when puls_ixh_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- pull ix hi + ix_ctrl <= pull_hi_ix; + addr_ctrl <= pulls_ad; + next_state <= puls_ixl_state; + + when puls_ixl_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read ix low + ix_ctrl <= pull_lo_ix; + addr_ctrl <= pulls_ad; + if ea(5) = '1' then + next_state <= puls_iyh_state; + elsif ea(6) = '1' then + next_state <= puls_uph_state; + elsif ea(7) = '1' then + next_state <= puls_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when puls_iyh_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- pull iy hi + iy_ctrl <= pull_hi_iy; + addr_ctrl <= pulls_ad; + next_state <= puls_iyl_state; + + when puls_iyl_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read iy low + iy_ctrl <= pull_lo_iy; + addr_ctrl <= pulls_ad; + if ea(6) = '1' then + next_state <= puls_uph_state; + elsif ea(7) = '1' then + next_state <= puls_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when puls_uph_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- pull up hi + up_ctrl <= pull_hi_up; + addr_ctrl <= pulls_ad; + next_state <= puls_upl_state; + + when puls_upl_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read up low + up_ctrl <= pull_lo_up; + addr_ctrl <= pulls_ad; + if ea(7) = '1' then + next_state <= puls_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when puls_pch_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- pull pc hi + pc_ctrl <= pull_hi_pc; + addr_ctrl <= pulls_ad; + next_state <= puls_pcl_state; + + when puls_pcl_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read pc low + pc_ctrl <= pull_lo_pc; + addr_ctrl <= pulls_ad; + lic <= '1'; + next_state <= fetch_state; + + -- + -- Enter here on pshu + -- ea holds post byte + -- + when pshu_state => + -- decrement up if any registers to be pushed + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(7 downto 0) = "00000000" then + up_ctrl <= latch_up; + else + up_ctrl <= load_up; + end if; + -- write idle bus + if ea(7) = '1' then + next_state <= pshu_pcl_state; + elsif ea(6) = '1' then + next_state <= pshu_spl_state; + elsif ea(5) = '1' then + next_state <= pshu_iyl_state; + elsif ea(4) = '1' then + next_state <= pshu_ixl_state; + elsif ea(3) = '1' then + next_state <= pshu_dp_state; + elsif ea(2) = '1' then + next_state <= pshu_accb_state; + elsif ea(1) = '1' then + next_state <= pshu_acca_state; + elsif ea(0) = '1' then + next_state <= pshu_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + -- + -- push PC onto U stack + -- + when pshu_pcl_state => + -- decrement up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + up_ctrl <= load_up; + -- write pc low + addr_ctrl <= pushu_ad; + dout_ctrl <= pc_lo_dout; + next_state <= pshu_pch_state; + + when pshu_pch_state => + -- decrement up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(6 downto 0) = "0000000" then + up_ctrl <= latch_up; + else + up_ctrl <= load_up; + end if; + -- write pc hi + addr_ctrl <= pushu_ad; + dout_ctrl <= pc_hi_dout; + if ea(6) = '1' then + next_state <= pshu_spl_state; + elsif ea(5) = '1' then + next_state <= pshu_iyl_state; + elsif ea(4) = '1' then + next_state <= pshu_ixl_state; + elsif ea(3) = '1' then + next_state <= pshu_dp_state; + elsif ea(2) = '1' then + next_state <= pshu_accb_state; + elsif ea(1) = '1' then + next_state <= pshu_acca_state; + elsif ea(0) = '1' then + next_state <= pshu_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshu_spl_state => + -- decrement up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + up_ctrl <= load_up; + -- write sp low + addr_ctrl <= pushu_ad; + dout_ctrl <= sp_lo_dout; + next_state <= pshu_sph_state; + + when pshu_sph_state => + -- decrement up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(5 downto 0) = "000000" then + up_ctrl <= latch_up; + else + up_ctrl <= load_up; + end if; + -- write sp hi + addr_ctrl <= pushu_ad; + dout_ctrl <= sp_hi_dout; + if ea(5) = '1' then + next_state <= pshu_iyl_state; + elsif ea(4) = '1' then + next_state <= pshu_ixl_state; + elsif ea(3) = '1' then + next_state <= pshu_dp_state; + elsif ea(2) = '1' then + next_state <= pshu_accb_state; + elsif ea(1) = '1' then + next_state <= pshu_acca_state; + elsif ea(0) = '1' then + next_state <= pshu_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshu_iyl_state => + -- decrement up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + up_ctrl <= load_up; + -- write iy low + addr_ctrl <= pushu_ad; + dout_ctrl <= iy_lo_dout; + next_state <= pshu_iyh_state; + + when pshu_iyh_state => + -- decrement up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(4 downto 0) = "00000" then + up_ctrl <= latch_up; + else + up_ctrl <= load_up; + end if; + -- write iy hi + addr_ctrl <= pushu_ad; + dout_ctrl <= iy_hi_dout; + if ea(4) = '1' then + next_state <= pshu_ixl_state; + elsif ea(3) = '1' then + next_state <= pshu_dp_state; + elsif ea(2) = '1' then + next_state <= pshu_accb_state; + elsif ea(1) = '1' then + next_state <= pshu_acca_state; + elsif ea(0) = '1' then + next_state <= pshu_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshu_ixl_state => + -- decrement up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + up_ctrl <= load_up; + -- write ix low + addr_ctrl <= pushu_ad; + dout_ctrl <= ix_lo_dout; + next_state <= pshu_ixh_state; + + when pshu_ixh_state => + -- decrement up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(3 downto 0) = "0000" then + up_ctrl <= latch_up; + else + up_ctrl <= load_up; + end if; + -- write ix hi + addr_ctrl <= pushu_ad; + dout_ctrl <= ix_hi_dout; + if ea(3) = '1' then + next_state <= pshu_dp_state; + elsif ea(2) = '1' then + next_state <= pshu_accb_state; + elsif ea(1) = '1' then + next_state <= pshu_acca_state; + elsif ea(0) = '1' then + next_state <= pshu_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshu_dp_state => + -- decrement up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(2 downto 0) = "000" then + up_ctrl <= latch_up; + else + up_ctrl <= load_up; + end if; + -- write dp + addr_ctrl <= pushu_ad; + dout_ctrl <= dp_dout; + if ea(2) = '1' then + next_state <= pshu_accb_state; + elsif ea(1) = '1' then + next_state <= pshu_acca_state; + elsif ea(0) = '1' then + next_state <= pshu_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshu_accb_state => + -- decrement up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(1 downto 0) = "00" then + up_ctrl <= latch_up; + else + up_ctrl <= load_up; + end if; + -- write accb + addr_ctrl <= pushu_ad; + dout_ctrl <= accb_dout; + if ea(1) = '1' then + next_state <= pshu_acca_state; + elsif ea(0) = '1' then + next_state <= pshu_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshu_acca_state => + -- decrement up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + if ea(0) = '0' then + up_ctrl <= latch_up; + else + up_ctrl <= load_up; + end if; + -- write acca + addr_ctrl <= pushu_ad; + dout_ctrl <= acca_dout; + if ea(0) = '1' then + next_state <= pshu_cc_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pshu_cc_state => + -- idle up + -- write cc + addr_ctrl <= pushu_ad; + dout_ctrl <= cc_dout; + lic <= '1'; + next_state <= fetch_state; + + -- + -- enter here on PULU + -- ea hold register mask + -- + when pulu_state => + -- idle UP + -- idle bus + if ea(0) = '1' then + next_state <= pulu_cc_state; + elsif ea(1) = '1' then + next_state <= pulu_acca_state; + elsif ea(2) = '1' then + next_state <= pulu_accb_state; + elsif ea(3) = '1' then + next_state <= pulu_dp_state; + elsif ea(4) = '1' then + next_state <= pulu_ixh_state; + elsif ea(5) = '1' then + next_state <= pulu_iyh_state; + elsif ea(6) = '1' then + next_state <= pulu_sph_state; + elsif ea(7) = '1' then + next_state <= pulu_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pulu_cc_state => + -- increment up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + up_ctrl <= load_up; + -- read cc + cc_ctrl <= pull_cc; + addr_ctrl <= pullu_ad; + if ea(1) = '1' then + next_state <= pulu_acca_state; + elsif ea(2) = '1' then + next_state <= pulu_accb_state; + elsif ea(3) = '1' then + next_state <= pulu_dp_state; + elsif ea(4) = '1' then + next_state <= pulu_ixh_state; + elsif ea(5) = '1' then + next_state <= pulu_iyh_state; + elsif ea(6) = '1' then + next_state <= pulu_sph_state; + elsif ea(7) = '1' then + next_state <= pulu_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pulu_acca_state => + -- increment up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + up_ctrl <= load_up; + -- read acca + acca_ctrl <= pull_acca; + addr_ctrl <= pullu_ad; + if ea(2) = '1' then + next_state <= pulu_accb_state; + elsif ea(3) = '1' then + next_state <= pulu_dp_state; + elsif ea(4) = '1' then + next_state <= pulu_ixh_state; + elsif ea(5) = '1' then + next_state <= pulu_iyh_state; + elsif ea(6) = '1' then + next_state <= pulu_sph_state; + elsif ea(7) = '1' then + next_state <= pulu_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pulu_accb_state => + -- increment up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + up_ctrl <= load_up; + -- read accb + accb_ctrl <= pull_accb; + addr_ctrl <= pullu_ad; + if ea(3) = '1' then + next_state <= pulu_dp_state; + elsif ea(4) = '1' then + next_state <= pulu_ixh_state; + elsif ea(5) = '1' then + next_state <= pulu_iyh_state; + elsif ea(6) = '1' then + next_state <= pulu_sph_state; + elsif ea(7) = '1' then + next_state <= pulu_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pulu_dp_state => + -- increment up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + up_ctrl <= load_up; + -- read dp + dp_ctrl <= pull_dp; + addr_ctrl <= pullu_ad; + if ea(4) = '1' then + next_state <= pulu_ixh_state; + elsif ea(5) = '1' then + next_state <= pulu_iyh_state; + elsif ea(6) = '1' then + next_state <= pulu_sph_state; + elsif ea(7) = '1' then + next_state <= pulu_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pulu_ixh_state => + -- increment up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + up_ctrl <= load_up; + -- read ix hi + ix_ctrl <= pull_hi_ix; + addr_ctrl <= pullu_ad; + next_state <= pulu_ixl_state; + + when pulu_ixl_state => + -- increment up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + up_ctrl <= load_up; + -- read ix low + ix_ctrl <= pull_lo_ix; + addr_ctrl <= pullu_ad; + if ea(5) = '1' then + next_state <= pulu_iyh_state; + elsif ea(6) = '1' then + next_state <= pulu_sph_state; + elsif ea(7) = '1' then + next_state <= pulu_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pulu_iyh_state => + -- increment up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + up_ctrl <= load_up; + -- read iy hi + iy_ctrl <= pull_hi_iy; + addr_ctrl <= pullu_ad; + next_state <= pulu_iyl_state; + + when pulu_iyl_state => + -- increment up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + up_ctrl <= load_up; + -- read iy low + iy_ctrl <= pull_lo_iy; + addr_ctrl <= pullu_ad; + if ea(6) = '1' then + next_state <= pulu_sph_state; + elsif ea(7) = '1' then + next_state <= pulu_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pulu_sph_state => + -- increment up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + up_ctrl <= load_up; + -- read sp hi + sp_ctrl <= pull_hi_sp; + addr_ctrl <= pullu_ad; + next_state <= pulu_spl_state; + + when pulu_spl_state => + -- increment up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + up_ctrl <= load_up; + -- read sp low + sp_ctrl <= pull_lo_sp; + addr_ctrl <= pullu_ad; + if ea(7) = '1' then + next_state <= pulu_pch_state; + else + lic <= '1'; + next_state <= fetch_state; + end if; + + when pulu_pch_state => + -- increment up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + up_ctrl <= load_up; + -- pull pc hi + pc_ctrl <= pull_hi_pc; + addr_ctrl <= pullu_ad; + next_state <= pulu_pcl_state; + + when pulu_pcl_state => + -- increment up + left_ctrl <= up_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + up_ctrl <= load_up; + -- read pc low + pc_ctrl <= pull_lo_pc; + addr_ctrl <= pullu_ad; + lic <= '1'; + next_state <= fetch_state; + + -- + -- pop the Condition codes + -- + when rti_cc_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read cc + cc_ctrl <= pull_cc; + addr_ctrl <= pulls_ad; + next_state <= rti_entire_state; + + -- + -- Added RTI cycle 11th July 2006 John Kent. + -- test the "Entire" Flag + -- that has just been popped off the stack + -- + when rti_entire_state => + -- + -- The Entire flag must be recovered from the stack + -- before testing. + -- + if cc(EBIT) = '1' then + next_state <= rti_acca_state; + else + next_state <= rti_pch_state; + end if; + + when rti_acca_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read acca + acca_ctrl <= pull_acca; + addr_ctrl <= pulls_ad; + next_state <= rti_accb_state; + + when rti_accb_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read accb + accb_ctrl <= pull_accb; + addr_ctrl <= pulls_ad; + next_state <= rti_dp_state; + + when rti_dp_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read dp + dp_ctrl <= pull_dp; + addr_ctrl <= pulls_ad; + next_state <= rti_ixh_state; + + when rti_ixh_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read ix hi + ix_ctrl <= pull_hi_ix; + addr_ctrl <= pulls_ad; + next_state <= rti_ixl_state; + + when rti_ixl_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read ix low + ix_ctrl <= pull_lo_ix; + addr_ctrl <= pulls_ad; + next_state <= rti_iyh_state; + + when rti_iyh_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read iy hi + iy_ctrl <= pull_hi_iy; + addr_ctrl <= pulls_ad; + next_state <= rti_iyl_state; + + when rti_iyl_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read iy low + iy_ctrl <= pull_lo_iy; + addr_ctrl <= pulls_ad; + next_state <= rti_uph_state; + + + when rti_uph_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read up hi + up_ctrl <= pull_hi_up; + addr_ctrl <= pulls_ad; + next_state <= rti_upl_state; + + when rti_upl_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- read up low + up_ctrl <= pull_lo_up; + addr_ctrl <= pulls_ad; + next_state <= rti_pch_state; + + when rti_pch_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- pull pc hi + pc_ctrl <= pull_hi_pc; + addr_ctrl <= pulls_ad; + next_state <= rti_pcl_state; + + when rti_pcl_state => + -- increment sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_add16; + sp_ctrl <= load_sp; + -- pull pc low + pc_ctrl <= pull_lo_pc; + addr_ctrl <= pulls_ad; + lic <= '1'; + next_state <= fetch_state; + + -- + -- here on NMI interrupt + -- Complete execute cycle of the last instruction. + -- If it was a dual operand instruction + -- + when int_nmi_state => + next_state <= int_nmi1_state; + + -- Idle bus cycle + when int_nmi1_state => + -- pre decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + iv_ctrl <= nmi_iv; + st_ctrl <= push_st; + return_state <= int_nmimask_state; + next_state <= int_entire_state; + + -- + -- here on IRQ interrupt + -- Complete execute cycle of the last instruction. + -- If it was a dual operand instruction + -- + when int_irq_state => + next_state <= int_irq1_state; + + -- pre decrement the sp + -- Idle bus cycle + when int_irq1_state => + -- pre decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + iv_ctrl <= irq_iv; + st_ctrl <= push_st; + return_state <= int_irqmask_state; + next_state <= int_entire_state; + + -- + -- here on FIRQ interrupt + -- Complete execution cycle of the last instruction + -- if it was a dual operand instruction + -- + when int_firq_state => + next_state <= int_firq1_state; + + -- Idle bus cycle + when int_firq1_state => + -- pre decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + iv_ctrl <= firq_iv; + st_ctrl <= push_st; + return_state <= int_firqmask_state; + next_state <= int_fast_state; + + -- + -- CWAI entry point + -- stack pointer already pre-decremented + -- mask condition codes + -- + when cwai_state => + -- AND CC with md + left_ctrl <= md_left; + right_ctrl <= zero_right; + alu_ctrl <= alu_andcc; + cc_ctrl <= load_cc; + st_ctrl <= push_st; + return_state <= int_cwai_state; + next_state <= int_entire_state; + + -- + -- wait here for an interrupt + -- + when int_cwai_state => + if (nmi_req = '1') then + iv_ctrl <= nmi_iv; + next_state <= int_nmimask_state; + -- + -- FIRQ & IRQ are level sensitive + -- + elsif (firq = '1') and (cc(FBIT) = '0') then + iv_ctrl <= firq_iv; + next_state <= int_firqmask_state; + + elsif (irq = '1') and (cc(IBIT) = '0') then + iv_ctrl <= irq_iv; + next_state <= int_irqmask_state; + else + next_state <= int_cwai_state; + end if; + + -- + -- State to mask I Flag and F Flag (NMI) + -- + when int_nmimask_state => + alu_ctrl <= alu_seif; + cc_ctrl <= load_cc; + next_state <= vect_hi_state; + + -- + -- State to mask I Flag and F Flag (FIRQ) + -- + when int_firqmask_state => + alu_ctrl <= alu_seif; + cc_ctrl <= load_cc; + next_state <= vect_hi_state; + + + -- + -- State to mask I Flag and F Flag (SWI) + -- + when int_swimask_state => + alu_ctrl <= alu_seif; + cc_ctrl <= load_cc; + next_state <= vect_hi_state; + + -- + -- State to mask I Flag only (IRQ) + -- + when int_irqmask_state => + alu_ctrl <= alu_sei; + cc_ctrl <= load_cc; + next_state <= vect_hi_state; + + -- + -- set Entire Flag on SWI, SWI2, SWI3 and CWAI, IRQ and NMI + -- before stacking all registers + -- + when int_entire_state => + -- set entire flag + alu_ctrl <= alu_see; + cc_ctrl <= load_cc; + next_state <= int_pcl_state; + + -- + -- clear Entire Flag on FIRQ + -- before stacking all registers + -- + when int_fast_state => + -- clear entire flag + alu_ctrl <= alu_cle; + cc_ctrl <= load_cc; + next_state <= int_pcl_state; + + when int_pcl_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write pc low + addr_ctrl <= pushs_ad; + dout_ctrl <= pc_lo_dout; + next_state <= int_pch_state; + + when int_pch_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write pc hi + addr_ctrl <= pushs_ad; + dout_ctrl <= pc_hi_dout; + if cc(EBIT) = '1' then + next_state <= int_upl_state; + else + next_state <= int_cc_state; + end if; + + when int_upl_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write up low + addr_ctrl <= pushs_ad; + dout_ctrl <= up_lo_dout; + next_state <= int_uph_state; + + when int_uph_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write ix hi + addr_ctrl <= pushs_ad; + dout_ctrl <= up_hi_dout; + next_state <= int_iyl_state; + + when int_iyl_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write ix low + addr_ctrl <= pushs_ad; + dout_ctrl <= iy_lo_dout; + next_state <= int_iyh_state; + + when int_iyh_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write ix hi + addr_ctrl <= pushs_ad; + dout_ctrl <= iy_hi_dout; + next_state <= int_ixl_state; + + when int_ixl_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write ix low + addr_ctrl <= pushs_ad; + dout_ctrl <= ix_lo_dout; + next_state <= int_ixh_state; + + when int_ixh_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write ix hi + addr_ctrl <= pushs_ad; + dout_ctrl <= ix_hi_dout; + next_state <= int_dp_state; + + when int_dp_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write accb + addr_ctrl <= pushs_ad; + dout_ctrl <= dp_dout; + next_state <= int_accb_state; + + when int_accb_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write accb + addr_ctrl <= pushs_ad; + dout_ctrl <= accb_dout; + next_state <= int_acca_state; + + when int_acca_state => + -- decrement sp + left_ctrl <= sp_left; + right_ctrl <= one_right; + alu_ctrl <= alu_sub16; + sp_ctrl <= load_sp; + -- write acca + addr_ctrl <= pushs_ad; + dout_ctrl <= acca_dout; + next_state <= int_cc_state; + + when int_cc_state => + -- write cc + addr_ctrl <= pushs_ad; + dout_ctrl <= cc_dout; + next_state <= saved_state; + + -- + -- According to the 6809 programming manual: + -- If an interrupt is received and is masked + -- or lasts for less than three cycles, the PC + -- will advance to the next instruction. + -- If an interrupt is unmasked and lasts + -- for more than three cycles, an interrupt + -- will be generated. + -- Note that I don't wait 3 clock cycles. + -- John Kent 11th July 2006 + -- + when sync_state => + lic <= '1'; + ba <= '1'; + -- + -- Version 1.28 2015-05-30 + -- Exit sync_state on interrupt. + -- If the interrupts are active + -- they will be caught in the state_machine process + -- and the interrupt service routine microcode will be executed. + -- Masked interrupts will exit the sync_state. + -- Moved from the state_machine process to the state_sequencer process + -- + if (firq = '1') or (irq = '1') then + next_state <= fetch_state; + else + next_state <= sync_state; + end if; + + when halt_state => + -- + -- 2011-10-30 John Kent + -- ba & bs should be high + ba <= '1'; + bs <= '1'; + if halt = '1' then + next_state <= halt_state; + else + next_state <= fetch_state; + end if; + + end case; + +-- +-- Ver 1.23 2011-10-30 John Kent +-- First instruction cycle might be +-- fetch_state +-- halt_state +-- int_nmirq_state +-- int_firq_state +-- + if fic = '1' then + -- + case op_code(7 downto 6) is + -- + -- ver 1.29 + -- hide last cycle of multiply in fetch + -- + when "00" => + case op_code(5 downto 0) is + when "111101" => -- mul + -- if bit 7 of ea set, add accd to md + left_ctrl <= accd_left; + if ea(7) = '1' then + right_ctrl <= md_right; + else + right_ctrl <= zero_right; + end if; + alu_ctrl <= alu_mul; + cc_ctrl <= load_cc; + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + when others => + null; + end case; + when "10" => -- acca + case op_code(3 downto 0) is + when "0000" => -- suba + left_ctrl <= acca_left; + right_ctrl <= md_right; + alu_ctrl <= alu_sub8; + cc_ctrl <= load_cc; + acca_ctrl <= load_acca; + when "0001" => -- cmpa + left_ctrl <= acca_left; + right_ctrl <= md_right; + alu_ctrl <= alu_sub8; + cc_ctrl <= load_cc; + when "0010" => -- sbca + left_ctrl <= acca_left; + right_ctrl <= md_right; + alu_ctrl <= alu_sbc; + cc_ctrl <= load_cc; + acca_ctrl <= load_acca; + when "0011" => + case pre_code is + when "00010000" => -- page 2 -- cmpd + left_ctrl <= accd_left; + right_ctrl <= md_right; + alu_ctrl <= alu_sub16; + cc_ctrl <= load_cc; + when "00010001" => -- page 3 -- cmpu + left_ctrl <= up_left; + right_ctrl <= md_right; + alu_ctrl <= alu_sub16; + cc_ctrl <= load_cc; + when others => -- page 1 -- subd + left_ctrl <= accd_left; + right_ctrl <= md_right; + alu_ctrl <= alu_sub16; + cc_ctrl <= load_cc; + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + end case; + when "0100" => -- anda + left_ctrl <= acca_left; + right_ctrl <= md_right; + alu_ctrl <= alu_and; + cc_ctrl <= load_cc; + acca_ctrl <= load_acca; + when "0101" => -- bita + left_ctrl <= acca_left; + right_ctrl <= md_right; + alu_ctrl <= alu_and; + cc_ctrl <= load_cc; + when "0110" => -- ldaa + left_ctrl <= acca_left; + right_ctrl <= md_right; + alu_ctrl <= alu_ld8; + cc_ctrl <= load_cc; + acca_ctrl <= load_acca; + when "0111" => -- staa + left_ctrl <= acca_left; + right_ctrl <= md_right; + alu_ctrl <= alu_st8; + cc_ctrl <= load_cc; + when "1000" => -- eora + left_ctrl <= acca_left; + right_ctrl <= md_right; + alu_ctrl <= alu_eor; + cc_ctrl <= load_cc; + acca_ctrl <= load_acca; + when "1001" => -- adca + left_ctrl <= acca_left; + right_ctrl <= md_right; + alu_ctrl <= alu_adc; + cc_ctrl <= load_cc; + acca_ctrl <= load_acca; + when "1010" => -- oraa + left_ctrl <= acca_left; + right_ctrl <= md_right; + alu_ctrl <= alu_ora; + cc_ctrl <= load_cc; + acca_ctrl <= load_acca; + when "1011" => -- adda + left_ctrl <= acca_left; + right_ctrl <= md_right; + alu_ctrl <= alu_add8; + cc_ctrl <= load_cc; + acca_ctrl <= load_acca; + when "1100" => + case pre_code is + when "00010000" => -- page 2 -- cmpy + left_ctrl <= iy_left; + right_ctrl <= md_right; + alu_ctrl <= alu_sub16; + cc_ctrl <= load_cc; + when "00010001" => -- page 3 -- cmps + left_ctrl <= sp_left; + right_ctrl <= md_right; + alu_ctrl <= alu_sub16; + cc_ctrl <= load_cc; + when others => -- page 1 -- cmpx + left_ctrl <= ix_left; + right_ctrl <= md_right; + alu_ctrl <= alu_sub16; + cc_ctrl <= load_cc; + end case; + when "1101" => -- bsr / jsr + null; + when "1110" => -- ldx + case pre_code is + when "00010000" => -- page 2 -- ldy + left_ctrl <= iy_left; + right_ctrl <= md_right; + alu_ctrl <= alu_ld16; + cc_ctrl <= load_cc; + iy_ctrl <= load_iy; + when others => -- page 1 -- ldx + left_ctrl <= ix_left; + right_ctrl <= md_right; + alu_ctrl <= alu_ld16; + cc_ctrl <= load_cc; + ix_ctrl <= load_ix; + end case; + when "1111" => -- stx + case pre_code is + when "00010000" => -- page 2 -- sty + left_ctrl <= iy_left; + right_ctrl <= md_right; + alu_ctrl <= alu_st16; + cc_ctrl <= load_cc; + when others => -- page 1 -- stx + left_ctrl <= ix_left; + right_ctrl <= md_right; + alu_ctrl <= alu_st16; + cc_ctrl <= load_cc; + end case; + when others => + null; + end case; + when "11" => -- accb dual op + case op_code(3 downto 0) is + when "0000" => -- subb + left_ctrl <= accb_left; + right_ctrl <= md_right; + alu_ctrl <= alu_sub8; + cc_ctrl <= load_cc; + accb_ctrl <= load_accb; + when "0001" => -- cmpb + left_ctrl <= accb_left; + right_ctrl <= md_right; + alu_ctrl <= alu_sub8; + cc_ctrl <= load_cc; + when "0010" => -- sbcb + left_ctrl <= accb_left; + right_ctrl <= md_right; + alu_ctrl <= alu_sbc; + cc_ctrl <= load_cc; + accb_ctrl <= load_accb; + when "0011" => -- addd + left_ctrl <= accd_left; + right_ctrl <= md_right; + alu_ctrl <= alu_add16; + cc_ctrl <= load_cc; + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + when "0100" => -- andb + left_ctrl <= accb_left; + right_ctrl <= md_right; + alu_ctrl <= alu_and; + cc_ctrl <= load_cc; + accb_ctrl <= load_accb; + when "0101" => -- bitb + left_ctrl <= accb_left; + right_ctrl <= md_right; + alu_ctrl <= alu_and; + cc_ctrl <= load_cc; + when "0110" => -- ldab + left_ctrl <= accb_left; + right_ctrl <= md_right; + alu_ctrl <= alu_ld8; + cc_ctrl <= load_cc; + accb_ctrl <= load_accb; + when "0111" => -- stab + left_ctrl <= accb_left; + right_ctrl <= md_right; + alu_ctrl <= alu_st8; + cc_ctrl <= load_cc; + when "1000" => -- eorb + left_ctrl <= accb_left; + right_ctrl <= md_right; + alu_ctrl <= alu_eor; + cc_ctrl <= load_cc; + accb_ctrl <= load_accb; + when "1001" => -- adcb + left_ctrl <= accb_left; + right_ctrl <= md_right; + alu_ctrl <= alu_adc; + cc_ctrl <= load_cc; + accb_ctrl <= load_accb; + when "1010" => -- orab + left_ctrl <= accb_left; + right_ctrl <= md_right; + alu_ctrl <= alu_ora; + cc_ctrl <= load_cc; + accb_ctrl <= load_accb; + when "1011" => -- addb + left_ctrl <= accb_left; + right_ctrl <= md_right; + alu_ctrl <= alu_add8; + cc_ctrl <= load_cc; + accb_ctrl <= load_accb; + when "1100" => -- ldd + left_ctrl <= accd_left; + right_ctrl <= md_right; + alu_ctrl <= alu_ld16; + cc_ctrl <= load_cc; + acca_ctrl <= load_hi_acca; + accb_ctrl <= load_accb; + when "1101" => -- std + left_ctrl <= accd_left; + right_ctrl <= md_right; + alu_ctrl <= alu_st16; + cc_ctrl <= load_cc; + when "1110" => -- ldu + case pre_code is + when "00010000" => -- page 2 -- lds + left_ctrl <= sp_left; + right_ctrl <= md_right; + alu_ctrl <= alu_ld16; + cc_ctrl <= load_cc; + sp_ctrl <= load_sp; + when others => -- page 1 -- ldu + left_ctrl <= up_left; + right_ctrl <= md_right; + alu_ctrl <= alu_ld16; + cc_ctrl <= load_cc; + up_ctrl <= load_up; + end case; + when "1111" => + case pre_code is + when "00010000" => -- page 2 -- sts + left_ctrl <= sp_left; + right_ctrl <= md_right; + alu_ctrl <= alu_st16; + cc_ctrl <= load_cc; + when others => -- page 1 -- stu + left_ctrl <= up_left; + right_ctrl <= md_right; + alu_ctrl <= alu_st16; + cc_ctrl <= load_cc; + end case; + when others => + null; + end case; + when others => + null; + end case; + + end if; -- first instruction cycle (fic) + lic_out <= lic; +end process; + +end rtl; + Index: trunk/rtl/VHDL/crtc6845.vhd =================================================================== --- trunk/rtl/VHDL/crtc6845.vhd (nonexistent) +++ trunk/rtl/VHDL/crtc6845.vhd (revision 130) @@ -0,0 +1,722 @@ +--===========================================================================-- +-- -- +-- S Y N T H E S I Z A B L E CRTC6845 C O R E -- +-- -- +-- www.opencores.org - January 2000 -- +-- This IP core adheres to the GNU public license. -- +-- -- +-- VHDL model of MC6845 compatible CRTC -- +-- -- +-- This model doesn't implement interlace mode. Everything else is -- +-- (probably) according to original MC6845 data sheet (except VTOTADJ). -- +-- -- +-- Implementation in Xilinx Virtex XCV50-6 runs at 50 MHz (character clock).-- +-- With external pixel generator this CRTC could handle 450MHz pixel rate -- +-- (see MC6845 data-sheet for typical application). -- +-- -- +-- Author: Damjan Lampret, lampret@opencores.org -- +-- Reworked: John Kent, dilbert57@opencores.org -- +-- -- +-- TO DO: -- +-- -- +-- - testbench -- +-- -- +-- - interlace mode support, extend VSYNC for V.Total Adjust value (R5) -- +-- -- +-- - verification in a real application -- +-- -- +--===========================================================================-- +-- +-- Revision History +-- +-- Version Date Author Modification +-- 1.0 2000-01-?? Damjan Lampret Original Version +-- 2.0 2012-04-07 John Kent Substantial rework for System09 +-- Added vertical synch width to hsw_reg +-- Made light pen strobe positive going +-- +library IEEE; + use ieee.std_logic_1164.all; + use IEEE.STD_LOGIC_ARITH.ALL; + use IEEE.STD_LOGIC_UNSIGNED.ALL; + use ieee.numeric_std.all; + +entity crtc6845 is + generic ( + DB_WIDTH : integer := 8; + MA_WIDTH : integer := 14; + RA_WIDTH : integer := 5 + ); + port ( + clk : in STD_LOGIC; -- cpu clock (falling edge) + rst : in STD_LOGIC; -- reset (active high) + cs : in STD_LOGIC; -- register chip select + addr : in STD_LOGIC; -- register select + rw : in STD_LOGIC; -- register read write + data_in : in STD_LOGIC_VECTOR(DB_WIDTH-1 downto 0); -- register data bus in + data_out : out STD_LOGIC_VECTOR(DB_WIDTH-1 downto 0); -- register data bus out + + chr_clk : in STD_LOGIC; -- character clock input (rising edge) + MA : out STD_LOGIC_VECTOR(MA_WIDTH-1 downto 0); -- memory address (characters) + RA : out STD_LOGIC_VECTOR(RA_WIDTH-1 downto 0); -- row address (character generator lines) + HSYNC : out STD_LOGIC; -- Horizontal synch + VSYNC : out STD_LOGIC; -- Vertical synch + dsp_ena : out STD_LOGIC; -- Display enable + cur_ena : out STD_LOGIC; -- Cursor enable + lpn_stb : in STD_LOGIC -- light pen strobe input (active high) + ); +end crtc6845; + +architecture rtl of crtc6845 is + +constant AR_WIDTH : integer := 5; + +-- +-- 6845 Register Index Numbers +-- +constant hto_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00000"; -- Horizontal Total (Characters) WO +constant hds_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00001"; -- Horizontal Displayed (Characters) WO +constant hsp_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00010"; -- Horizontal Synch position (Characters) WO +constant hsw_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00011"; -- Sync Width (Ver & Hor) (SL / Chars) WO +constant vto_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00100"; -- Vertical Total (Char Rows) WO +constant adj_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00101"; -- Vertical Total Adjust (Scan Lines) WO +constant vds_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00110"; -- Vertical Displayed (Char Rows) WO +constant vsp_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "00111"; -- Vertical Synch position (Char Rows) WO +constant imd_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01000"; -- Interlace Mode & Skew WO +constant sln_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01001"; -- Maximum Scan Line Address (Scan Lines) WO +constant cur_s_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01010"; -- Cursor Start (Scan Lines) WO Bit 5 BP, Bit 6 BE +constant cur_e_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01011"; -- Cursor End (Scan Lines) WO +constant sta_h_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01100"; -- Start Address High RW +constant sta_l_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01101"; -- Start Address Low RW +constant cur_h_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01110"; -- Cursor Position High RW +constant cur_l_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "01111"; -- Cusror Position Low RW +constant lpn_h_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "10000"; -- Light Pen Position High RO +constant lpn_l_ind : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0) := "10001"; -- Light Pen Position Low RO + +-- +-- I/O address register +-- +signal ind_reg : STD_LOGIC_VECTOR(AR_WIDTH-1 downto 0); + +-- +-- 6845 Registers R0-R17 +-- +signal hto_reg : STD_LOGIC_VECTOR(7 downto 0); -- Horizontal Total (Chars) WO +signal hds_reg : STD_LOGIC_VECTOR(7 downto 0); -- Horizontal Display (Chars) WO +signal hsp_reg : STD_LOGIC_VECTOR(7 downto 0); -- Horizontal Synch Position (Chars) WO +signal hsw_reg : STD_LOGIC_VECTOR(7 downto 0); -- Horizontal Synch Width (Chars) WO +signal vto_reg : STD_LOGIC_VECTOR(6 downto 0); -- Vertical Total (Rows) WO +signal adj_reg : STD_LOGIC_VECTOR(4 downto 0); -- Vertical Total Adjust (Lines) WO +signal vds_reg : STD_LOGIC_VECTOR(6 downto 0); -- Vertcal Display (Rows) WO +signal vsp_reg : STD_LOGIC_VECTOR(6 downto 0); -- Vertical Synch Position (Rows) WO +signal imd_reg : STD_LOGIC_VECTOR(1 downto 0); -- Interlace Mode & Skew WO +signal sln_reg : STD_LOGIC_VECTOR(4 downto 0); -- Maximum Scan Line Address (Lines) WO +signal cur_s_reg : STD_LOGIC_VECTOR(6 downto 0); -- Cursor Start (Lines) WO +signal cur_e_reg : STD_LOGIC_VECTOR(4 downto 0); -- Cursor End (Lines) WO +signal sta_h_reg : STD_LOGIC_VECTOR(5 downto 0); -- Start Address High RW +signal sta_l_reg : STD_LOGIC_VECTOR(7 downto 0); -- Start Address Low RW +signal cur_h_reg : STD_LOGIC_VECTOR(5 downto 0); -- Cursor Position High RW +signal cur_l_reg : STD_LOGIC_VECTOR(7 downto 0); -- Cursor Position Low RW +signal lpn_h_reg : STD_LOGIC_VECTOR(5 downto 0); -- Light Pen Address High RO +signal lpn_l_reg : STD_LOGIC_VECTOR(7 downto 0); -- Light Pen Address Low RO + +-- +-- Counters +-- +signal hor_ctr : STD_LOGIC_VECTOR( 7 downto 0); -- Horizontal Counter (Chars) +signal hsw_ctr : STD_LOGIC_VECTOR( 3 downto 0); -- Horizontal Synch Width Counter (Chars) +signal sln_ctr : STD_LOGIC_VECTOR( 4 downto 0); -- Scan Line Counter (Lines) +signal ver_ctr : STD_LOGIC_VECTOR( 6 downto 0); -- Vertical Counter (Rows) +signal vsw_ctr : STD_LOGIC_VECTOR( 3 downto 0); -- Vertical Synch widtrh Counter (Lines) +signal row_ctr : STD_LOGIC_VECTOR(13 downto 0); -- Vertical Row counter +signal lag_ctr : STD_LOGIC_VECTOR(13 downto 0); -- Linear Address Generator Counter +signal bnk_ctr : STD_LOGIC_VECTOR( 4 downto 0); -- Blink Counter + +-- +-- Interconnect signals +-- +signal hor_end : STD_LOGIC; -- Horizontal display end +signal ver_end : STD_LOGIC; -- Vertical display end +signal hor_syn : STD_LOGIC; -- Horizontal Synch +signal ver_syn : STD_LOGIC; -- Vertical Synch +signal hor_dsp : STD_LOGIC; -- Horizontal Display Enable +signal ver_dsp : STD_LOGIC; -- Vertical Display Enable +signal hor_rst : STD_LOGIC; -- Horizontal Reset (End of Line) +signal ver_rst : STD_LOGIC; -- Vertical Reset (End of Frame) +signal sln_rst : STD_LOGIC; -- Scan Line Reset (End of Row) +signal sln_adj : STD_LOGIC; -- Scan Line Adjust (End of Frame) +signal cur_act : STD_LOGIC; -- Cursor active + +begin + +-- +-- Read CRTC6845 registers +-- +crtc_read: process(addr, ind_reg, sta_h_reg, sta_l_reg, cur_h_reg, cur_l_reg, lpn_h_reg, lpn_l_reg ) +begin + if addr = '0' then + -- + -- Read register address + -- + data_out(AR_WIDTH-1 downto 0) <= ind_reg; + data_out(7 downto AR_WIDTH) <= (others=>'0'); + else + -- + -- Read register value + -- + case ind_reg is + when sta_h_ind => + data_out <= "00" & sta_h_reg; + when sta_l_ind => + data_out <= sta_l_reg; + when cur_h_ind => + data_out <= "00" & cur_h_reg; + when cur_l_ind => + data_out <= cur_l_reg; + when lpn_h_ind => + data_out <= "00" & lpn_h_reg; + when lpn_l_ind => + data_out <= lpn_l_reg; + when others => + data_out <= (others => '0'); + end case; + end if; +end process; + +-- +-- Write CRTC registers +-- +crtc_write: process(clk, rst, cs, rw, addr, data_in) +begin + if falling_edge(clk) then + if rst = '1' then + ind_reg <= b"0" & x"0"; + hto_reg <= x"65"; + hds_reg <= x"50"; + hsp_reg <= x"56"; + hsw_reg <= x"F9"; + sln_reg <= '0' & x"b"; + vto_reg <= b"001" & x"8"; --18 + adj_reg <= b"0" & x"a"; + vds_reg <= b"001" & x"8"; --18 + vsp_reg <= b"001" & x"8"; --18 + imd_reg <= b"00"; + cur_s_reg <= b"000" & x"0"; + cur_e_reg <= b"0" & x"B"; + sta_h_reg <= b"00" & x"0"; + sta_l_reg <= x"80"; + cur_h_reg <= b"00" & x"0"; + cur_l_reg <= x"80"; + + elsif cs = '1' and rw = '0' then + if addr = '0' then + ind_reg <= data_in(AR_WIDTH-1 downto 0); + else + case ind_reg is + when hto_ind => + hto_reg <= data_in; + when hds_ind => + hds_reg <= data_in; + when hsp_ind => + hsp_reg <= data_in; + when hsw_ind => + hsw_reg <= data_in; + when sln_ind => + sln_reg <= data_in(4 downto 0); + when vto_ind => + vto_reg <= data_in(6 downto 0); + when adj_ind => + adj_reg <= data_in(4 downto 0); + when vds_ind => + vds_reg <= data_in(6 downto 0); + when vsp_ind => + vsp_reg <= data_in(6 downto 0); + when imd_ind => + imd_reg <= data_in(1 downto 0); + when cur_s_ind => + cur_s_reg <= data_in(6 downto 0); + when cur_e_ind => + cur_e_reg <= data_in(4 downto 0); + when sta_h_ind => + sta_h_reg <= data_in(5 downto 0); + when sta_l_ind => + sta_l_reg <= data_in; + when cur_h_ind => + cur_h_reg <= data_in(5 downto 0); + when cur_l_ind => + cur_l_reg <= data_in; + when others => + null; + end case; + end if; -- addr + end if; -- cs + end if; -- E + +end process; + +-------------------------------------------- +-- Horizontal Counter -- +-------------------------------------------- +-- +-- hor_ctr (horizontal counter) increments +-- until it reaches the horizontal total +-- then resets to zero +-- +crtc_hor_ctr_p : process(chr_clk, rst, hor_rst, hor_ctr) +begin + if rising_edge(chr_clk) then + if rst = '1' then + hor_ctr <= (others => '0'); + else + if hor_rst = '1' then + hor_ctr <= (others => '0'); + else + hor_ctr <= hor_ctr + 1; + end if; + end if; + end if; +end process; + +-------------------------------------------- +-- Horizontal Reset -- +-------------------------------------------- +-- +-- hor_rst (horizontal reset) goes high +-- for one horizontal character cycle +-- when the horizontal counte reaches +-- the horizontal total, then it goes low +-- +crtc_hor_rst_p : process(hor_ctr, hto_reg) +begin + if hor_ctr = hto_reg then + hor_rst <= '1'; + else + hor_rst <= '0'; + end if; +end process; + +-------------------------------------------- +-- Horizontal Display End -- +-------------------------------------------- +-- +-- hor_end (horizontal end) goes high +-- for one horizontal character clock cycles +-- when the horizontal counter reaches +-- the horizontal display count +-- +crtc_hor_end_p: process(hor_ctr, hds_reg) +begin + if hor_ctr = hds_reg then + hor_end <= '1'; + else + hor_end <= '0'; + end if; +end process; + +-------------------------------------------- +-- Horizontal Display Enable -- +-------------------------------------------- +-- +-- Horizontal display goes high on a +-- horizontal reset and goes low at +-- horizontal end. +-- +crtc_hor_dsp_p: process(chr_clk, rst, hor_rst, hor_end ) +begin + + if rising_edge( chr_clk ) then + if rst = '1' then + hor_dsp <= '0'; + elsif hor_rst = '1' and hor_end = '0' then + hor_dsp <= '1'; + elsif hor_rst = '0' and hor_end = '1' then + hor_dsp <= '0'; + end if; + end if; +end process; + +-------------------------------------------- +-- Horizontal Horizontal Synch -- +-------------------------------------------- +-- +-- hor_syn (horizontal synch) goes high +-- when the horizontal counter reaches +-- the the value in the horizontal synch position +-- register. It is reset when the horizontal +-- synch width counter reaches the value +-- in the horizontal synch width register +-- +crtc_hor_syn_p: process(chr_clk, rst, hor_ctr, hsp_reg, hsw_reg, hor_syn) +begin + if rising_edge(chr_clk) then + if rst = '1' then + hor_syn <= '0'; + elsif hor_ctr = hsp_reg then + hor_syn <= '1'; + elsif hsw_ctr = hsw_reg(3 downto 0) then + hor_syn <= '0'; + end if; + end if; + HSYNC <= hor_syn; + +end process; + +-------------------------------------------- +-- Horizontal Synch Width Counter -- +-------------------------------------------- +-- +-- The horizaontal synch width counter +-- increments each character clock cycle +-- while the horizontal synch pulse is high +-- It is reset when horizontal synch goes low +-- +crtc_hsw_ctr_p: process(chr_clk, rst, hor_syn, hsw_ctr) +begin + if rising_edge(chr_clk) then + if rst = '1' then + hsw_ctr <= (others => '0'); + else + if hor_syn = '1' then + hsw_ctr <= hsw_ctr + 1; + else + hsw_ctr <= (others => '0'); + end if; + end if; + end if; +end process; + +-------------------------------------------- +-- Scan Line Counter -- +-------------------------------------------- +-- +-- The Scan line counter increments +-- when horizontal reset goes high. +-- It is reset when the scan line counter +-- reaches the value in the scan line register +-- The Scan line counter is used to generate +-- the row address of the character generator +-- +crtc_sln_ctr_p: process(chr_clk, rst, hor_rst, sln_rst, sln_ctr ) +begin + if rising_edge(chr_clk) then + if rst = '1' then + sln_ctr <= (others => '0'); + elsif sln_rst = '1' then + sln_ctr <= (others => '0'); + elsif hor_rst = '1' then + sln_ctr <= sln_ctr + 1; + end if; + end if; + RA <= sln_ctr; +end process; + +-------------------------------------------- +-- Scan Line Reset -- +-------------------------------------------- +-- +-- Scan line reset is goes high when the +-- scan line counter reaches the value in +-- the scan line register and is zero otherwise +-- +crtc_sln_rst_p: process(sln_reg, sln_ctr) +begin + if sln_ctr = sln_reg then + sln_rst <= '1'; + else + sln_rst <= '0'; + end if; +end process; + +-------------------------------------------- +-- Scan Line Adjust -- +-------------------------------------------- +-- +-- Scan line Adjust goes high when the +-- scan line counter reaches the value +-- in the scan line adjust register. +-- It is use to reset the vertical counter +-- when it reaches the vertical total +-- +crtc_sln_adj_p: process(sln_ctr, adj_reg) +begin + if sln_ctr = adj_reg then + sln_adj <= '1'; + else + sln_adj <= '0'; + end if; +end process; + +-------------------------------------------- +-- Vertical Row Counter -- +-------------------------------------------- +-- +-- The Vertical Row counter is incremenented +-- when there is a scan line reset and there +-- is a horizontal reset. +-- The vertical row counter is reset when +-- there is a vertical reset due to the +-- vertical counter reaching the value in +-- the vertical total register and a +-- scan line adjust signal is generated +-- +ctrc_ver_ctr_p: process(chr_clk, rst, sln_rst) +begin + if rising_edge(chr_clk) then + if rst = '1' then + ver_ctr <= (others => '0'); + elsif ver_rst = '1' then + ver_ctr <= (others => '0'); + elsif sln_rst = '1' and hor_rst = '1' then + ver_ctr <= ver_ctr + 1; + end if; + end if; +end process; + +-------------------------------------------- +-- Vertical Reset -- +-------------------------------------------- +-- +-- Vertical reset is generated when the +-- vertical counter reaches the value in +-- the vertical total register and the +-- scan line counter reaches the scan +-- line adjust register value +-- +ctrc_ver_rst_p: process(ver_ctr, vto_reg, sln_adj ) +begin + + if ver_ctr = vto_reg and sln_adj = '1' then + ver_rst <= '1'; + else + ver_rst <= '0'; + end if; + +end process; + +-------------------------------------------- +-- Vertical Display End Process -- +-------------------------------------------- +-- +-- Vertical end is generated when the +-- vertical counter reaches the value in +-- the display end register +-- +crtc_ver_end_p: process(ver_ctr, vds_reg) +begin + if ver_ctr = vds_reg then + ver_end <= '1'; + else + ver_end <= '0'; + end if; +end process; + +-------------------------------------------- +-- Vertical Display Enable -- +-------------------------------------------- + +crtc_ver_dsp_p: process(chr_clk, rst, ver_rst, ver_end ) +begin + + if rising_edge( chr_clk ) then + if rst = '1' then + ver_dsp <= '0'; + elsif ver_rst = '1' and ver_end = '0' then + ver_dsp <= '1'; + elsif ver_rst = '0' and ver_end = '1' then + ver_dsp <= '0'; + end if; + end if; + +end process; + +-------------------------------------------- +-- Vertical Synch Width Counter -- +-------------------------------------------- +-- +-- The Vertical Synch Width Counter +-- is incremented when vertical synch goes high +-- as a result of the Vertical Counter reaching +-- the Vertical Synch Width Position and horizontal +-- reset goes high. +-- The Vertical synch width counter is reset +-- when Vertical synch goes low. +-- +crtc_vsw_ctr_p: process(chr_clk, rst, hor_rst, ver_ctr, vsp_reg, vsw_ctr) +begin + if rising_edge(chr_clk) then + if rst = '1' then + vsw_ctr <= (others => '0'); + elsif ver_syn = '0' then + vsw_ctr <= (others => '0'); + elsif ver_syn = '1' and hor_rst = '1' then + vsw_ctr <= vsw_ctr + 1; + end if; + end if; +end process; + +-------------------------------------------- +-- Vertical Synch -- +-------------------------------------------- +-- +-- The Vertical Synch goes high when the +-- vertical counter reaches the value in the +-- vertical synch position register. +-- It is reset when the vertical synch width +-- counter reaches 16. +-- +crtc_ver_syn_p: process(chr_clk, rst, ver_ctr, vsp_reg, vsw_ctr, hsw_reg, ver_syn) +begin + if rising_edge(chr_clk) then + if rst = '1' then + ver_syn <= '0'; + elsif ver_ctr = vsp_reg then + ver_syn <= '1'; + elsif vsw_ctr = hsw_reg(7 downto 4) then + ver_syn <= '0'; + end if; + end if; + VSYNC <= ver_syn; +end process; + +-------------------------------------------- +-- Vertical Row Counter -- +-------------------------------------------- +-- +-- The character row counter is incremented +-- by the horizontal display count +-- on a scan line reset and a horizontal reset. +-- It is reset to the start address on a vertical reset +-- +crtc_row_ctr_p: process(chr_clk, rst, sln_rst, ver_rst, hor_rst, sta_h_reg, sta_l_reg) +begin + if rising_edge(chr_clk) then + if rst = '1' then + row_ctr <= sta_h_reg & sta_l_reg; + elsif sln_rst = '1' and hor_rst = '1' then + row_ctr <= row_ctr + hds_reg; + if ver_rst = '1' then + row_ctr <= sta_h_reg & sta_l_reg; + end if; + end if; + end if; +end process; + +-------------------------------------------- +-- Display Enable -- +-------------------------------------------- +-- +-- Display enable is active when both +-- horizantal display and vertical displays +-- are active +-- +crtc_dsp_ena_p: process(hor_dsp, ver_dsp) +begin + + dsp_ena <= hor_dsp and ver_dsp; + +end process; + + +-------------------------------------------- +-- Linear Address Generator -- +-------------------------------------------- + +crtc_lag_p: process(chr_clk, rst, hor_rst, sta_h_reg, sta_l_reg, lag_ctr) +begin + if rising_edge(chr_clk) then + if rst = '1' then + lag_ctr <= sta_h_reg & sta_l_reg; + else + if hor_rst = '1' then + lag_ctr <= row_ctr; + end if; + lag_ctr <= lag_ctr + 1; + end if; + end if; + MA <= lag_ctr; +end process; + +-------------------------------------------- +-- Cursor Control Unit Instantiation -- +-------------------------------------------- +-- +-- Cursor active when the Linear Address Generator +-- reaches the value in the Cursor position register +-- +crtc_cur_act_p: process(lag_ctr, cur_h_reg, cur_l_reg) +begin + if lag_ctr = (cur_h_reg & cur_l_reg) then + cur_act <= '1'; + else + cur_act <= '0'; + end if; +end process; + +-------------------------------------------- +-- Cursor Blink Counter -- +-------------------------------------------- +-- +-- The Cursor Blink Counter increments +-- every frame +-- +crtc_blink_ctr_p: process (chr_clk, rst, hor_rst, ver_rst) +begin + if rising_edge(chr_clk) then + if rst = '1' then + bnk_ctr <= (others => '0'); + elsif hor_rst = '1' and ver_rst = '1' then + bnk_ctr <= bnk_ctr + 1; + end if; + end if; +end process; + +-------------------------------------------- +-- Cursor Enable -- +-------------------------------------------- +-- +-- The Cursor is enabled when the Scan line +-- counter is great or equal to the Cursor Start Line +-- and the scan line counter is less than or equal +-- to the Cursor End line and the Cusor is active +-- +crtc_cur_ena_p: process (sln_ctr, cur_s_reg, cur_e_reg, cur_act, bnk_ctr) +begin + if sln_ctr >= cur_s_reg(4 downto 0) and sln_ctr <= cur_e_reg and cur_act = '1' then + case cur_s_reg(6 downto 5) is + when "00" => + cur_ena <= '1'; + when "10" => + cur_ena <= bnk_ctr(3); + when "11" => + cur_ena <= bnk_ctr(4); + when others => + cur_ena <= '0'; + end case; + else + cur_ena <= '0'; + end if; +end process; + +-------------------------------------------- +-- Light Pen Capture -- +-------------------------------------------- +-- +-- The light pen resister is loaded +-- when ther is a high on the light +-- pen strobe input +-- +ctrc_lpn_stb_p: process(chr_clk, rst, lpn_stb) +begin + if rising_edge(chr_clk) then + if rst = '1' then + lpn_h_reg <= (others => '0'); + lpn_l_reg <= (others => '0'); + elsif lpn_stb = '1' then + lpn_h_reg <= lag_ctr(13 downto 8); + lpn_l_reg <= lag_ctr(7 downto 0); + end if; + end if; +end process; + +end rtl; +
trunk/rtl/VHDL/crtc6845.vhd Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/rtl/VHDL/divs32_s2.vhd =================================================================== --- trunk/rtl/VHDL/divs32_s2.vhd (nonexistent) +++ trunk/rtl/VHDL/divs32_s2.vhd (revision 130) @@ -0,0 +1,331 @@ +--===========================================================================-- +-- -- +-- Synthesizable unsigned 32 bit integer divider -- +-- -- +--===========================================================================-- +-- +-- File name : divs32.vhd +-- +-- Entity name : sdiv32 +-- +-- Purpose : Implements a 32 bit signed integer divider +-- +-- Dependencies : ieee.std_logic_1164 +-- ieee.numeric_std +-- ieee.std_logic_unsigned +-- +-- Author : John E. Kent +-- +-- Email : dilbert57@opencores.org +-- +-- Web : http://opencores.org/project,system09 +-- +-- Registers : +-- 0 Dividend 1st Byte MSB +-- 1 2nd Byte +-- 2 3rd Byte +-- 3 4th Byte LSB +-- 4 Divisor 1st Byte MSB +-- 5 2nd Byte +-- 6 3rd Byte +-- 7 4th Byte LSB +-- 8 quotient 1st Byte MSB +-- 9 2nd Byte +-- 10 3rd Byte +-- 11 4th byte LSB +-- 12 Remainder 1st Byte MSB +-- 13 2nd Byte +-- 14 3rd Byte +-- 15 4th byte LSB +-- +-- 32 bit unsigned binary division. +-- +-- Write the most significant byte of the dividend at the 0th register first +-- down to the least significant byte of the divisor in the 7th register. +-- Writing the least significant byte of the divisor will start the division. +-- +-- The 32 bit division will take 32 clock cycles. +-- There is no status register so the CPU must execute a software delay +-- to wait 32 clock cycles after the least significant byte of the divisor +-- is written before reading the quotient of the division or the remainder. +-- +-- The dividend and divisor input registers are read/writable +-- The quotient and remainder output registers are read only. +-- The quotient register holds the integer part of the result of the division. +-- The remainder register holds the dividend modulo the divisor. +-- +-- Copyright (C) 2012 - 2014 John Kent +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program 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 General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +--===========================================================================-- +-- -- +-- Revision History -- +-- -- +--===========================================================================-- +-- +-- Version Author Date Changes +-- +-- 0.1 John Kent 2012-04-06 Initial version +-- 0.2 John Kent 2014-05-07 Replaced Status register with 4 byte remainder +-- 0.3 John Kent 2016-02-04 Shortend result_temp to 33 bits so subtraction is faster. +-- Add hold output to pause CPU until result is valid. +-- 0.4 John Kent 2018-03-21 Changed unsigned udiv32 to signed sdiv32 +-- +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + use ieee.std_logic_unsigned.all; +--library unisim; +-- use unisim.vcomponents.all; + +entity sdiv32 is + port ( + -- + -- CPU Interface signals + -- + clk : in std_logic; -- CPU Clock + rst : in std_logic; -- Reset input (active high) + cs : in std_logic; -- Chip Select + addr : in std_logic_vector(3 downto 0); -- Register Select + rw : in std_logic; -- Read / Not Write + data_in : in std_logic_vector(7 downto 0); -- Data Bus In + data_out : out std_logic_vector(7 downto 0); -- Data Bus Out + hold : out std_logic -- Result access hold + ); +end sdiv32; +--================== End of entity ==============================-- + +------------------------------------------------------------------- +-- Architecture for unsigned 32 bit integer divider interface +------------------------------------------------------------------- + +architecture rtl of sdiv32 is + +signal dividend : std_logic_vector(31 downto 0) := (others => '0'); +signal divisor : std_logic_vector(31 downto 0) := (others => '0'); +signal result : std_logic_vector(63 downto 0) := (others => '0'); +signal quotient : std_logic_vector(31 downto 0) := (others => '0'); +signal remainder : std_logic_vector(31 downto 0) := (others => '0'); +signal count : std_logic_vector( 4 downto 0) := (others => '0'); +signal req_flag : std_logic := '0'; -- Request Division +signal act_flag : std_logic := '0'; -- Division Active + +begin + +-- +-- Write registers +-- +sdiv32_write : process( clk, rst, cs, rw, addr, data_in, req_flag, act_flag ) +begin + if rst = '1' then + dividend <= (others=> '0'); -- reset the dividend to zero + divisor <= (others=> '0'); -- reset the divisor to zero + req_flag <= '0'; -- the default state is stopped + elsif falling_edge( clk ) then + -- + -- write to registers + -- + if (cs = '1') and (rw = '0') then + case addr is + when "0000" => + dividend(31 downto 24) <= data_in; + when "0001" => + dividend(23 downto 16) <= data_in; + when "0010" => + dividend(15 downto 8) <= data_in; + when "0011" => + dividend( 7 downto 0) <= data_in; + when "0100" => + divisor(31 downto 24) <= data_in; + when "0101" => + divisor(23 downto 16) <= data_in; + when "0110" => + divisor(15 downto 8) <= data_in; + when "0111" => + divisor( 7 downto 0) <= data_in; + -- + -- writing the last byte of the divisor + -- should pulse the request flag high for one cycle + -- starting the division, + -- provided the previous division has finished + -- + if (req_flag = '0') and (act_flag = '0') then + req_flag <= '1'; + end if; + when others => + null; + end case; + end if; + end if; -- rst/clk + if (req_flag = '1') and (act_flag = '1') then + req_flag <= '0'; + end if; + hold <= cs and rw and addr(3) and act_flag; +end process; + +-- +-- Read registers +-- +sdiv32_read : process( addr, dividend, divisor, quotient, remainder ) +begin + case addr is + when "0000" => + data_out <= dividend(31 downto 24); + when "0001" => + data_out <= dividend(23 downto 16); + when "0010" => + data_out <= dividend(15 downto 8); + when "0011" => + data_out <= dividend( 7 downto 0); + when "0100" => + data_out <= divisor(31 downto 24); + when "0101" => + data_out <= divisor(23 downto 16); + when "0110" => + data_out <= divisor(15 downto 8); + when "0111" => + data_out <= divisor( 7 downto 0); + when "1000" => + data_out <= quotient(31 downto 24); + when "1001" => + data_out <= quotient(23 downto 16); + when "1010" => + data_out <= quotient(15 downto 8); + when "1011" => + data_out <= quotient( 7 downto 0); + when "1100" => + data_out <= remainder(31 downto 24); + when "1101" => + data_out <= remainder(23 downto 16); + when "1110" => + data_out <= remainder(15 downto 8); + when "1111" => + data_out <= remainder(7 downto 0); + when others => + null; + end case; +end process; + +-- +-- When the finish flag is high and the start flag goes high, +-- start the division by clearing the finish flag +-- When the finish flag is low and the count reaches 31 +sdiv32_divide : process( rst, clk, dividend, divisor, remainder, req_flag, act_flag, count ) +variable result_temp : std_logic_vector(32 downto 0); +begin + if (rst = '1') then + result <= (others=>'0'); + result_temp := (others=>'0'); + remainder <= (others=>'0'); + quotient <= (others=>'0'); + count <= (others=>'0'); + act_flag <= '0'; -- default state is inactive + elsif falling_edge( clk ) then + -- + -- activate the division if the last division was complete + -- i.e. the active flag was clear + -- and the last byte of the divisor was just written + -- i.e. the request flag was pulsed high for one clock cycle + -- + if (req_flag = '1') and (act_flag = '0') then + -- + -- put dividend in result and make positive + -- + result(63 downto 32) <= (others => '0'); + if dividend(31) = '0' then + result(31 downto 0) <= dividend; -- Dividend in the Least Significant Word of remainder + else + result(31 downto 0) <= "00000000000000000000000000000000" - dividend; + end if; + -- + -- Initialize temp variables + -- + result_temp := (others => '0'); -- Clear the remainder temp variable + -- + -- reset bit counter and activate division + -- + count <= (others => '0'); -- Clear the bit counter + act_flag <= '1'; -- Flag division in progress + + elsif (req_flag = '0') and (act_flag = '1') then -- If active flag is set the division must be in progress + -- + -- if dividend positive, subrtact divisor + -- if dividend negative, add divisor + -- + if (divisor(31)) = '0' then + result_temp := result(63 downto 31) - (divisor(31) & divisor); -- subtract the divisor from the remainder if positive + else + result_temp := result(63 downto 31) + (divisor(31) & divisor); -- add the divisor to the remainder if negative + end if; + + -- + -- if carry clear from add or subract + -- update the remainder + -- + if result_temp(32) = '0' then -- if the remainder temp carry is clear + result(63 downto 32) <= result_temp(31 downto 0); -- update the result with remainder + else + result(63 downto 32) <= result(62 downto 31); -- otherwise shift remainder up one bit + end if; + + -- + -- shift the quotient up one bit + -- The LSBit is the inverted remainder carry + -- + result(31 downto 1) <= result(30 downto 0); -- shift lower remainder up one bit + result(0) <= not result_temp(32); -- shift quotient in bottom of remainder + + -- + -- 32 bit division should take 32 clock cycles + -- + count <= count + "00001"; + -- + -- When the count reaches the 31st cycle of the division + -- flag that the division is complete by clrearing the active flag. + -- + if count = "11111" then + act_flag <= '0'; -- flag division complete + end if; + + end if; -- start/finish + + -- + -- negating the result will take another clock cycle. + -- If the cpu is held on a read access of the + -- quotient or remainder it may get the wrong result. + -- + + -- + -- quotient has sign of dividend exclusive or divisor + -- + if( (dividend(31) xor divisor(31)) = '0') then + quotient <= result(31 downto 0); + else + quotient <= "00000000000000000000000000000000" - result(31 downto 0); + end if; + + -- + -- remainder has sign of dividend + -- + if dividend(31) = '0' then + remainder <= result(63 downto 32); + else + remainder <= "00000000000000000000000000000000" - result(63 downto 32); + end if; + + end if; -- rst/clk +end process; + +end rtl; -- end of architecture \ No newline at end of file Index: trunk/rtl/VHDL/divu32.vhd =================================================================== --- trunk/rtl/VHDL/divu32.vhd (nonexistent) +++ trunk/rtl/VHDL/divu32.vhd (revision 130) @@ -0,0 +1,292 @@ +--===========================================================================-- +-- -- +-- Synthesizable unsigned 32 bit integer divider -- +-- -- +--===========================================================================-- +-- +-- File name : divu32.vhd +-- +-- Entity name : udiv32 +-- +-- Purpose : Implements a 32 bit unsigned integer divider +-- +-- Dependencies : ieee.std_logic_1164 +-- ieee.numeric_std +-- ieee.std_logic_unsigned +-- +-- Author : John E. Kent +-- +-- Email : dilbert57@opencores.org +-- +-- Web : http://opencores.org/project,system09 +-- +-- Registers : +-- 0 Dividend 1st Byte MSB +-- 1 2nd Byte +-- 2 3rd Byte +-- 3 4th Byte LSB +-- 4 Divisor 1st Byte MSB +-- 5 2nd Byte +-- 6 3rd Byte +-- 7 4th Byte LSB +-- 8 Result 1st Byte MSB +-- 9 2nd Byte +-- 10 3rd Byte +-- 11 4th byte LSB +-- 12 Remainder 1st Byte MSB +-- 13 2nd Byte +-- 14 3rd Byte +-- 15 4th byte LSB +-- +-- 32 bit unsigned binary division. +-- +-- Write the most significant byte of the dividend at the 0th register first +-- down to the least significant byte of the divisor in the 7th register. +-- Writing the least significant byte of the divisor will start the division. +-- +-- The 32 bit division will take 32 clock cycles. +-- There is no status register so the CPU must execute a software delay +-- to wait 32 clock cycles after the least significant byte of the divisor +-- is written before reading the result of the division or the remainder. +-- +-- The dividend and divisor input registers are read/writable +-- The result and remainder output registers are read only. +-- The result register holds the integer part of the result of the division. +-- The remainder register holds the dividend modulo the divisor. +-- +-- Copyright (C) 2012 - 2014 John Kent +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program 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 General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +--===========================================================================-- +-- -- +-- Revision History -- +-- -- +--===========================================================================-- +-- +-- Version Author Date Changes +-- +-- 0.1 John Kent 2012-04-06 Initial version +-- 0.2 John Kent 2014-05-07 Replaced Status register with 4 byte remainder +-- + +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + use ieee.std_logic_unsigned.all; +--library unisim; +-- use unisim.vcomponents.all; + +entity udiv32 is + port ( + -- + -- CPU Interface signals + -- + clk : in std_logic; -- CPU Clock + rst : in std_logic; -- Reset input (active high) + cs : in std_logic; -- Chip Select + addr : in std_logic_vector(3 downto 0); -- Register Select + rw : in std_logic; -- Read / Not Write + data_in : in std_logic_vector(7 downto 0); -- Data Bus In + data_out : out std_logic_vector(7 downto 0) -- Data Bus Out + ); +end udiv32; +--================== End of entity ==============================-- + +------------------------------------------------------------------- +-- Architecture for unsigned 32 bit integer divider interface +------------------------------------------------------------------- + +architecture rtl of udiv32 is + +signal dividend : std_logic_vector(31 downto 0) := (others => '0'); +signal divisor : std_logic_vector(31 downto 0) := (others => '0'); +signal result : std_logic_vector(31 downto 0) := (others => '0'); +signal count : std_logic_vector( 4 downto 0) := (others => '0'); +signal start_flag : std_logic := '0'; +signal finish_flag : std_logic := '0'; + +signal dividend_temp : std_logic_vector(64 downto 0); +signal divisor_temp : std_logic_vector(64 downto 0); + +begin + +-- +-- Write registers +-- +udiv32_write : process( clk, rst, data_in, finish_flag ) +begin + if falling_edge( clk ) then + if rst = '1' then + dividend <= (others=> '0'); -- reset the dividend to zero + divisor <= (others=> '0'); -- reset the divisor to zero + start_flag <= '0'; -- the default state is stopped + else + -- + -- start bit is normally reset + -- + start_flag <= '0'; + -- + -- write to registers + -- + if (cs = '1') and (rw = '0') then + case addr is + when "0000" => + dividend(31 downto 24) <= data_in; + when "0001" => + dividend(23 downto 16) <= data_in; + when "0010" => + dividend(15 downto 8) <= data_in; + when "0011" => + dividend( 7 downto 0) <= data_in; + when "0100" => + divisor(31 downto 24) <= data_in; + when "0101" => + divisor(23 downto 16) <= data_in; + when "0110" => + divisor(15 downto 8) <= data_in; + when "0111" => + divisor( 7 downto 0) <= data_in; + -- + -- writing the last byte of the divisor + -- should pulse the start flag high for one cycle + -- starting the division, + -- provided the previous division has finished + -- + if (finish_flag = '1') then + start_flag <= '1'; + end if; + when others => + null; + end case; + end if; + end if; -- rst + end if; -- clk +end process; + +-- +-- Read registers +-- +udiv32_read : process( addr, dividend, divisor, result, dividend_temp ) +begin + case addr is + when "0000" => + data_out <= dividend(31 downto 24); + when "0001" => + data_out <= dividend(23 downto 16); + when "0010" => + data_out <= dividend(15 downto 8); + when "0011" => + data_out <= dividend( 7 downto 0); + when "0100" => + data_out <= divisor(31 downto 24); + when "0101" => + data_out <= divisor(23 downto 16); + when "0110" => + data_out <= divisor(15 downto 8); + when "0111" => + data_out <= divisor( 7 downto 0); + when "1000" => + data_out <= result(31 downto 24); + when "1001" => + data_out <= result(23 downto 16); + when "1010" => + data_out <= result(15 downto 8); + when "1011" => + data_out <= result( 7 downto 0); + when "1100" => + data_out <= dividend_temp(31 downto 24); + when "1101" => + data_out <= dividend_temp(23 downto 16); + when "1110" => + data_out <= dividend_temp(15 downto 8); + when "1111" => + data_out <= dividend_temp( 7 downto 0); + when others => + null; + end case; +end process; + +-- +-- When the finish flag is high and the start flag goes high, +-- start the division by clearing the finish flag +-- When the finish flag is low and the count reaches 31 +udiv32_divide : process( rst, clk, start_flag, finish_flag ) +variable result_temp : std_logic_vector(64 downto 0); +begin + if falling_edge( clk ) then + if (rst = '1') then + dividend_temp <= (others=>'0'); + divisor_temp <= (others=>'0'); + result_temp := (others=>'0'); + result <= (others=>'0'); + count <= (others=>'0'); + finish_flag <= '1'; -- default state is finished + else + -- + -- start the division if the last division was complete + -- i.e. the finish flag was set + -- and the last byte of the divisor was just written + -- i.e. the start flag was pulsed high for one clock cycle + -- + if (start_flag = '1') and (finish_flag = '1') then + dividend_temp(64) <= '0'; -- dividend carry bit + dividend_temp(63 downto 32) <= (others => '0'); -- zero MSW + dividend_temp(31 downto 0) <= dividend(31 downto 0); -- Mantissa in the bottom + + divisor_temp(64) <= '0'; -- divisor carry bit + divisor_temp(63) <= '0'; -- + divisor_temp(62 downto 31) <= divisor(31 downto 0); -- divisor starts off one bit down in MSW + divisor_temp(30 downto 0) <= (others => '0'); -- bottom of divisor is zero + + result_temp := (others => '0'); -- clear the result variable + + count <= (others => '0'); -- zero the bit counter + finish_flag <= '0'; -- flag that the division is in progress + + elsif ( finish_flag = '0' ) then -- if finish flag is clear the division must be in progress + + result_temp := dividend_temp - divisor_temp; -- subtract the divisor from the dividend + + if result_temp(64) = '0' then -- if the result carry is clear + dividend_temp <= result_temp; -- update the dividend variable with the result variable + end if; + -- + -- shift divisor down one bit + -- + divisor_temp(62 downto 0) <= divisor_temp(63 downto 1); + -- + -- shift the result up one bit + -- The LSBit is the inverted result carry + -- + result(0) <= not result_temp(64); + result(31 downto 1) <= result(30 downto 0); + -- + -- 32 bit division should take 32 clock cycles + -- + count <= count + "00001"; + -- + -- When the count reaches the 31st cycle of the division + -- flag that the division is complete by setting the finish flag. + -- + if count = "11111" then + finish_flag <= '1'; -- flag division complete + end if; + + end if; -- start/finish + end if; -- rst + end if; -- clk +end process; + +end rtl; -- end of architecture \ No newline at end of file
trunk/rtl/VHDL/divu32.vhd Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/rtl/VHDL/divu32_s2.vhd =================================================================== --- trunk/rtl/VHDL/divu32_s2.vhd (nonexistent) +++ trunk/rtl/VHDL/divu32_s2.vhd (revision 130) @@ -0,0 +1,280 @@ +--===========================================================================-- +-- -- +-- Synthesizable unsigned 32 bit integer divider -- +-- -- +--===========================================================================-- +-- +-- File name : divu32.vhd +-- +-- Entity name : udiv32 +-- +-- Purpose : Implements a 32 bit unsigned integer divider +-- +-- Dependencies : ieee.std_logic_1164 +-- ieee.numeric_std +-- ieee.std_logic_unsigned +-- +-- Author : John E. Kent +-- +-- Email : dilbert57@opencores.org +-- +-- Web : http://opencores.org/project,system09 +-- +-- Registers : +-- 0 Dividend 1st Byte MSB +-- 1 2nd Byte +-- 2 3rd Byte +-- 3 4th Byte LSB +-- 4 Divisor 1st Byte MSB +-- 5 2nd Byte +-- 6 3rd Byte +-- 7 4th Byte LSB +-- 8 Result 1st Byte MSB +-- 9 2nd Byte +-- 10 3rd Byte +-- 11 4th byte LSB +-- 12 Remainder 1st Byte MSB +-- 13 2nd Byte +-- 14 3rd Byte +-- 15 4th byte LSB +-- +-- 32 bit unsigned binary division. +-- +-- Write the most significant byte of the dividend at the 0th register first +-- down to the least significant byte of the divisor in the 7th register. +-- Writing the least significant byte of the divisor will start the division. +-- +-- The 32 bit division will take 32 clock cycles. +-- There is no status register so the CPU must execute a software delay +-- to wait 32 clock cycles after the least significant byte of the divisor +-- is written before reading the result of the division or the remainder. +-- +-- The dividend and divisor input registers are read/writable +-- The result and remainder output registers are read only. +-- The result register holds the integer part of the result of the division. +-- The remainder register holds the dividend modulo the divisor. +-- +-- Copyright (C) 2012 - 2014 John Kent +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program 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 General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +--===========================================================================-- +-- -- +-- Revision History -- +-- -- +--===========================================================================-- +-- +-- Version Author Date Changes +-- +-- 0.1 John Kent 2012-04-06 Initial version +-- 0.2 John Kent 2014-05-07 Replaced Status register with 4 byte remainder +-- 0.3 John Kent 2016-02-04 Shortend result_temp to 33 bits so subtraction is faster. +-- Add hold output to pause CPU until result is valid. + +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + use ieee.std_logic_unsigned.all; +--library unisim; +-- use unisim.vcomponents.all; + +entity udiv32 is + port ( + -- + -- CPU Interface signals + -- + clk : in std_logic; -- CPU Clock + rst : in std_logic; -- Reset input (active high) + cs : in std_logic; -- Chip Select + addr : in std_logic_vector(3 downto 0); -- Register Select + rw : in std_logic; -- Read / Not Write + data_in : in std_logic_vector(7 downto 0); -- Data Bus In + data_out : out std_logic_vector(7 downto 0); -- Data Bus Out + hold : out std_logic -- Result access hold + ); +end udiv32; +--================== End of entity ==============================-- + +------------------------------------------------------------------- +-- Architecture for unsigned 32 bit integer divider interface +------------------------------------------------------------------- + +architecture rtl of udiv32 is + +signal dividend : std_logic_vector(31 downto 0) := (others => '0'); +signal divisor : std_logic_vector(31 downto 0) := (others => '0'); +signal result : std_logic_vector(31 downto 0) := (others => '0'); +signal remainder : std_logic_vector(63 downto 0) := (others => '0'); +signal count : std_logic_vector( 4 downto 0) := (others => '0'); +signal req_flag : std_logic := '0'; -- Request Division +signal act_flag : std_logic := '0'; -- Division Active + +begin + +-- +-- Write registers +-- +udiv32_write : process( clk, rst, cs, rw, addr, data_in, act_flag, req_flag ) +begin + if rst = '1' then + dividend <= (others=> '0'); -- reset the dividend to zero + divisor <= (others=> '0'); -- reset the divisor to zero + req_flag <= '0'; -- the default state is stopped + elsif falling_edge( clk ) then + -- + -- write to registers + -- + if (cs = '1') and (rw = '0') then + case addr is + when "0000" => + dividend(31 downto 24) <= data_in; + when "0001" => + dividend(23 downto 16) <= data_in; + when "0010" => + dividend(15 downto 8) <= data_in; + when "0011" => + dividend( 7 downto 0) <= data_in; + when "0100" => + divisor(31 downto 24) <= data_in; + when "0101" => + divisor(23 downto 16) <= data_in; + when "0110" => + divisor(15 downto 8) <= data_in; + when "0111" => + divisor( 7 downto 0) <= data_in; + -- + -- writing the last byte of the divisor + -- should pulse the request flag high for one cycle + -- starting the division, + -- provided the previous division has finished + -- + if (act_flag = '0') and (req_flag = '0') then + req_flag <= '1'; + end if; + when others => + null; + end case; + end if; + end if; -- rst/clk + if( act_flag = '1') and (req_flag = '1') then + req_flag <= '0'; + end if; + hold <= cs and rw and addr(3) and act_flag; +end process; + +-- +-- Read registers +-- +udiv32_read : process( addr, dividend, divisor, result, remainder ) +begin + case addr is + when "0000" => + data_out <= dividend(31 downto 24); + when "0001" => + data_out <= dividend(23 downto 16); + when "0010" => + data_out <= dividend(15 downto 8); + when "0011" => + data_out <= dividend( 7 downto 0); + when "0100" => + data_out <= divisor(31 downto 24); + when "0101" => + data_out <= divisor(23 downto 16); + when "0110" => + data_out <= divisor(15 downto 8); + when "0111" => + data_out <= divisor( 7 downto 0); + when "1000" => + data_out <= result(31 downto 24); + when "1001" => + data_out <= result(23 downto 16); + when "1010" => + data_out <= result(15 downto 8); + when "1011" => + data_out <= result( 7 downto 0); + when "1100" => + data_out <= remainder(63 downto 56); + when "1101" => + data_out <= remainder(55 downto 48); + when "1110" => + data_out <= remainder(47 downto 40); + when "1111" => + data_out <= remainder(39 downto 32); + when others => + null; + end case; +end process; + +-- +-- When the finish flag is high and the start flag goes high, +-- start the division by clearing the finish flag +-- When the finish flag is low and the count reaches 31 +udiv32_divide : process( rst, clk, req_flag, act_flag ) +variable remainder_temp : std_logic_vector(32 downto 0); +begin + if (rst = '1') then + remainder <= (others=>'0'); + remainder_temp := (others=>'0'); + result <= (others=>'0'); + count <= (others=>'0'); + act_flag <= '0'; -- default state is inactive + elsif falling_edge( clk ) then + -- + -- activate the division if the last division was complete + -- i.e. the active flag was clear + -- and the last byte of the divisor was just written + -- i.e. the request flag was pulsed high for one clock cycle + -- + if (req_flag = '1') and (act_flag = '0') then + remainder(63 downto 32) <= (others => '0'); -- Clear Most Significant Word of remainder + remainder(31 downto 0) <= dividend(31 downto 0); -- Dividend in the Least Significant Word of remainder + remainder_temp := (others => '0'); -- Clear the remainder temp variable + count <= (others => '0'); -- Clear the bit counter + act_flag <= '1'; -- Flag division in progress + + elsif (req_flag = '0') and (act_flag = '1') then -- If active flag is set the division must be in progress + + remainder_temp := (remainder(63 downto 31)) - ("0" & divisor); -- subtract the divisor from the remainder + + if remainder_temp(32) = '0' then -- if the remainder temp carry is clear + remainder(63 downto 32) <= remainder_temp(31 downto 0); -- update the remainder variable with remainder temp + else + remainder(63 downto 32) <= remainder(62 downto 31); -- shift remainder up one bit + end if; + remainder(31 downto 1) <= remainder(30 downto 0); -- shift remainder up one bit + remainder(0) <= '0'; + + -- + -- shift the result up one bit + -- The LSBit is the inverted remainder carry + -- + result(31 downto 1) <= result(30 downto 0); + result(0) <= not remainder_temp(32); + -- + -- 32 bit division should take 32 clock cycles + -- + count <= count + "00001"; + -- + -- When the count reaches the 31st cycle of the division + -- flag that the division is complete by clrearing the active flag. + -- + if count = "11111" then + act_flag <= '0'; -- flag division complete + end if; + + end if; -- start/finish + end if; -- rst/clk +end process; + +end rtl; -- end of architecture \ No newline at end of file
trunk/rtl/VHDL/divu32_s2.vhd Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/rtl/VHDL/muls32_s2.vhd =================================================================== --- trunk/rtl/VHDL/muls32_s2.vhd (nonexistent) +++ trunk/rtl/VHDL/muls32_s2.vhd (revision 130) @@ -0,0 +1,287 @@ +--===========================================================================-- +-- -- +-- umul32.vhd - Synthesizable 32 bit unsigned integer multiplier -- +-- For FPGAs without hardware multiplier blocks -- +-- -- +--===========================================================================-- +-- +-- File name : muls32_S2.vhd +-- +-- Entity name : smul32 +-- +-- Purpose : Implements a 32 bit x 32 bit signed integer multiplier +-- Produces 64 bit result. +-- Consists of 16 x 8 bit registers. +-- 4 x 8bit read/write registers for 32 bit multiplicand. +-- 4 x 8bit read/write registers for 32 bit multiplier. +-- 8 x 8bit read only register for 64 bit result. +-- There is no control or status register. +-- Must wait 32 clock cycles for result after writing LSByte of multiplier +-- Designed for FPGAs which don't have hardware multiplier blocks +-- such as Spartan 2/2E (which are no longer supported by current Xilinx software) +-- +-- Dependencies : ieee.std_logic_1164 +-- ieee.std_logic_unsigned +-- unisim.vcomponents +-- +-- Author : John E. Kent +-- +-- Email : dilbert57@opencores.org +-- +-- Web : http://opencores.org/project,system09 +-- +-- Registers : +-- +-- 0 R/W multiplicand input Most Significant Byte +-- 1 R/W multiplicand input +-- 2 R/W multiplicand input +-- 3 R/W multiplicand input Least Significant Byte +-- 4 R/W multiplier input Most Significant Byte +-- 5 R/W multiplier input +-- 6 R/W multiplier input +-- 7 R/W multiplier input Least Significant Byte +-- 8 R/O result output Most Significant Byte +-- 9 R/O result output +-- 10 R/O result output +-- 11 R/O result output +-- 12 R/O result output +-- 13 R/O result output +-- 14 R/O result output +-- 15 R/O result output Least Significant Byte +-- +-- Copyright (C) 2010 - 2012 John Kent +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program 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 General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +--===========================================================================-- +-- -- +-- Revision History -- +-- -- +--===========================================================================-- +-- +-- Version Author Date Description +-- +-- 0.1 John Kent 2008-09-07 Initial version +-- 0.2 John Kent 2010-06-17 Header & GPL added +-- 0.3 John Kent 2012-04-06 converted into umul32 +-- 0.4 John Kent 2016-02-04 Version without hardware multiply +-- 0.5 John Kent 2018-03-21 converted into smul32 +-- + +library ieee; + use ieee.std_logic_1164.all; + use ieee.std_logic_unsigned.all; +--library unisim; +-- use unisim.vcomponents.all; + +entity smul32 is + port ( + clk : in std_logic; + rst : in std_logic; + cs : in std_logic; + rw : in std_logic; + addr : in std_logic_vector(3 downto 0); + data_in : in std_logic_vector(7 downto 0); + data_out : out std_logic_vector(7 downto 0); + hold : out std_logic + ); +end entity; + +architecture rtl of smul32 is + +-- +-- registers +-- +signal multiplicand : std_logic_vector(31 downto 0) := (others=>'0'); +signal multiplier : std_logic_vector(31 downto 0) := (others=>'0'); +signal result : std_logic_vector(64 downto 0) := (others=>'0'); + +signal multiplier_temp : std_logic_vector(31 downto 0) := (others=>'0'); + +signal count : std_logic_vector(4 downto 0); -- bit counter +signal req_flag : std_logic := '0'; +signal act_flag : std_logic := '0'; + +begin + +--------------------------------- +-- +-- Write Multiplier Registers +-- +--------------------------------- + +smul32_write : process( clk, rst, cs, rw, addr, data_in, req_flag, act_flag ) +begin + if rst = '1' then + multiplicand <= (others => '0'); + multiplier <= (others => '0'); + req_flag <= '0'; + elsif falling_edge( clk ) then + if (cs = '1') and (rw = '0') then + case addr is + when "0000" => + multiplicand(31 downto 24) <= data_in; + when "0001" => + multiplicand(23 downto 16) <= data_in; + when "0010" => + multiplicand(15 downto 8) <= data_in; + when "0011" => + multiplicand( 7 downto 0) <= data_in; + when "0100" => + multiplier(31 downto 24) <= data_in; + when "0101" => + multiplier(23 downto 16) <= data_in; + when "0110" => + multiplier(15 downto 8) <= data_in; + when "0111" => + multiplier( 7 downto 0) <= data_in; + if (req_flag = '0') and (act_flag = '0') then + req_flag <= '1'; + end if; + when others => + null; + end case; + end if; -- clk + if (req_flag = '1') and (act_flag = '1') then + req_flag <= '0'; + end if; + hold <= cs and rw and addr(3) and act_flag; + end if; -- rst +end process; + +--------------------------------- +-- +-- Read Multiplier Registers +-- +--------------------------------- + +smul32_read : process( addr, multiplicand, multiplier, result ) +begin + case addr is + when "0000" => + data_out <= multiplicand(31 downto 24); + when "0001" => + data_out <= multiplicand(23 downto 16); + when "0010" => + data_out <= multiplicand(15 downto 8); + when "0011" => + data_out <= multiplicand( 7 downto 0); + when "0100" => + data_out <= multiplier(31 downto 24); + when "0101" => + data_out <= multiplier(23 downto 16); + when "0110" => + data_out <= multiplier(15 downto 8); + when "0111" => + data_out <= multiplier( 7 downto 0); + when "1000" => + data_out <= result(63 downto 56); + when "1001" => + data_out <= result(55 downto 48); + when "1010" => + data_out <= result(47 downto 40); + when "1011" => + data_out <= result(39 downto 32); + when "1100" => + data_out <= result(31 downto 24); + when "1101" => + data_out <= result(23 downto 16); + when "1110" => + data_out <= result(15 downto 8); + when "1111" => + data_out <= result( 7 downto 0); + when others => + null; + end case; + +end process; + +--------------------------------- +-- +-- Perform 32 x 32 multiply +-- +--------------------------------- +-- +-- When the active flag is clear and the request flag goes high, +-- start the multiplication by setting the active flag +-- When the active flag is high and the count reaches 31 +-- reset the active flag +-- +smul32_multiply : process( rst, clk, req_flag, act_flag ) +variable result_temp : std_logic_vector(32 downto 0); +begin + if (rst = '1') then + multiplier_temp <= (others=>'0'); + result <= (others=>'0'); + count <= (others=>'0'); + act_flag <= '0'; -- default state is inactive + elsif falling_edge( clk ) then + -- + -- start the division if the last division was complete + -- i.e. the active flag was clear + -- and the last byte of the divisor was just written + -- i.e. the request flag was pulsed high for one clock cycle + -- + if (req_flag = '1') and (act_flag = '0') then + if multiplier(31) = '0' then + multiplier_temp(31 downto 0) <= multiplier(31 downto 0); -- Get Multiplier into temp + else + multiplier_temp(31 downto 0) <= "00000000000000000000000000000000" - multiplier(31 downto 0); + end if; + result <= (others => '0'); -- Clear the result + count <= (others => '0'); -- Zero the bit counter + act_flag <= '1'; -- Flag that the multiplication is in progress + + elsif (req_flag = '0') and ( act_flag = '1' ) then -- if active flag is set the multiplication must be in progress + + result_temp := (result(63) & result(63 downto 32)); + if multiplier_temp(0) = '1' then + if multiplier(31) = '0' then -- if most significant bit of multiplicand is clear + result_temp := (result(63) & result(63 downto 32)) + (multiplicand(31) & multiplicand); -- add the multiplicand to the msbits of the result + else + result_temp := (result(63) & result(63 downto 32)) - (multiplicand(31) & multiplicand); -- otherwise subtract the multiplicand from the msbits of the result + end if; + end if; + + -- + -- shift the result down one bit + -- leave sign bit of result + -- + result(30 downto 0) <= result(31 downto 1); + result(63 downto 31) <= result_temp(32 downto 0); + + -- + -- shift multiplier temp down one bit + -- extend sign bit of multiplier temp + -- + multiplier_temp(30 downto 0) <= multiplier_temp(31 downto 1); + + -- + -- 32 bit multiplication should take 32 clock cycles + -- + count <= count + "00001"; + -- + -- When the count reaches the 31st cycle of the division + -- flag that the multiplication is complete by setting the finish flag. + -- + if count = "11111" then + act_flag <= '0'; -- flag Multiplication complete + end if; + + end if; -- start/finish + end if; -- rst/clk +end process; + +end rtl; + Index: trunk/rtl/VHDL/mulu32_s2.vhd =================================================================== --- trunk/rtl/VHDL/mulu32_s2.vhd (nonexistent) +++ trunk/rtl/VHDL/mulu32_s2.vhd (revision 130) @@ -0,0 +1,276 @@ +--===========================================================================-- +-- -- +-- umul32.vhd - Synthesizable 32 bit unsigned integer multiplier -- +-- For FPGAs without hardware multiplier blocks -- +-- -- +--===========================================================================-- +-- +-- File name : mulu32_S2.vhd +-- +-- Entity name : umul32 +-- +-- Purpose : Implements a 32 bit x 32 bit unsigned integer multiplier +-- Produces 64 bit result. +-- Consists of 16 x 8 bit registers. +-- 4 x 8bit read/write registers for 32 bit multiplicand. +-- 4 x 8bit read/write registers for 32 bit multiplier. +-- 8 x 8bit read only register for 64 bit result. +-- There is no control or status register. +-- Must wait 32 clock cycles for result after writing LSByte of multiplier +-- Designed for FPGAs which don't have hardware multiplier blocks +-- such as Spartan 2/2E (which are no longer supported by current Xilinx software) +-- +-- Dependencies : ieee.std_logic_1164 +-- ieee.std_logic_unsigned +-- unisim.vcomponents +-- +-- Author : John E. Kent +-- +-- Email : dilbert57@opencores.org +-- +-- Web : http://opencores.org/project,system09 +-- +-- Registers : +-- +-- 0 R/W multiplicand input Most Significant Byte +-- 1 R/W multiplicand input +-- 2 R/W multiplicand input +-- 3 R/W multiplicand input Least Significant Byte +-- 4 R/W multiplier input Most Significant Byte +-- 5 R/W multiplier input +-- 6 R/W multiplier input +-- 7 R/W multiplier input Least Significant Byte +-- 8 R/O result output Most Significant Byte +-- 9 R/O result output +-- 10 R/O result output +-- 11 R/O result output +-- 12 R/O result output +-- 13 R/O result output +-- 14 R/O result output +-- 15 R/O result output Least Significant Byte +-- +-- Copyright (C) 2010 - 2012 John Kent +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program 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 General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +--===========================================================================-- +-- -- +-- Revision History -- +-- -- +--===========================================================================-- +-- +-- Version Author Date Description +-- +-- 0.1 John Kent 2008-09-07 Initial version +-- 0.2 John Kent 2010-06-17 Header & GPL added +-- 0.3 John Kent 2012-04-06 converted into umul32 +-- 0.4 John Kent 2016-02-04 Version without hardware multiply +-- + +library ieee; + use ieee.std_logic_1164.all; + use ieee.std_logic_unsigned.all; +--library unisim; +-- use unisim.vcomponents.all; + +entity umul32 is + port ( + clk : in std_logic; + rst : in std_logic; + cs : in std_logic; + rw : in std_logic; + addr : in std_logic_vector(3 downto 0); + data_in : in std_logic_vector(7 downto 0); + data_out : out std_logic_vector(7 downto 0); + hold : out std_logic + ); +end entity; + +architecture rtl of umul32 is + +-- +-- registers +-- +signal multiplicand : std_logic_vector(31 downto 0) := (others=>'0'); +signal multiplier : std_logic_vector(31 downto 0) := (others=>'0'); +signal result : std_logic_vector(64 downto 0) := (others=>'0'); + +signal multiplier_temp : std_logic_vector(31 downto 0) := (others=>'0'); + +signal count : std_logic_vector(4 downto 0); -- bit counter +signal req_flag : std_logic := '0'; +signal act_flag : std_logic := '0'; + +begin + +--------------------------------- +-- +-- Write Multiplier Registers +-- +--------------------------------- + +umul32_write : process( clk, rst, cs, rw, addr, data_in, act_flag, req_flag ) +begin + if rst = '1' then + multiplicand <= (others => '0'); + multiplier <= (others => '0'); + req_flag <= '0'; + elsif falling_edge( clk ) then + if (cs = '1') and (rw = '0') then + case addr is + when "0000" => + multiplicand(31 downto 24) <= data_in; + when "0001" => + multiplicand(23 downto 16) <= data_in; + when "0010" => + multiplicand(15 downto 8) <= data_in; + when "0011" => + multiplicand( 7 downto 0) <= data_in; + when "0100" => + multiplier(31 downto 24) <= data_in; + when "0101" => + multiplier(23 downto 16) <= data_in; + when "0110" => + multiplier(15 downto 8) <= data_in; + when "0111" => + multiplier( 7 downto 0) <= data_in; + if (act_flag = '0') and (req_flag <= '0') then + req_flag <= '1'; + end if; + when others => + null; + end case; + end if; -- cs + if (act_flag = '1') and (req_flag = '1') then + req_flag <= '0'; + end if; + hold <= cs and rw and addr(3) and act_flag; + end if; -- rst/clk +end process; + +--------------------------------- +-- +-- Read Multiplier Registers +-- +--------------------------------- + +umul32_read : process( addr, multiplicand, multiplier, result ) +begin + case addr is + when "0000" => + data_out <= multiplicand(31 downto 24); + when "0001" => + data_out <= multiplicand(23 downto 16); + when "0010" => + data_out <= multiplicand(15 downto 8); + when "0011" => + data_out <= multiplicand( 7 downto 0); + when "0100" => + data_out <= multiplier(31 downto 24); + when "0101" => + data_out <= multiplier(23 downto 16); + when "0110" => + data_out <= multiplier(15 downto 8); + when "0111" => + data_out <= multiplier( 7 downto 0); + when "1000" => + data_out <= result(63 downto 56); + when "1001" => + data_out <= result(55 downto 48); + when "1010" => + data_out <= result(47 downto 40); + when "1011" => + data_out <= result(39 downto 32); + when "1100" => + data_out <= result(31 downto 24); + when "1101" => + data_out <= result(23 downto 16); + when "1110" => + data_out <= result(15 downto 8); + when "1111" => + data_out <= result( 7 downto 0); + when others => + null; + end case; + +end process; + +--------------------------------- +-- +-- Perform 32 x 32 multiply +-- +--------------------------------- +-- +-- When the active flag is clear and the request flag goes high, +-- start the multiplication by setting the active flag +-- When the active flag is high and the count reaches 31 +-- reset the active flag +-- +umul32_multiply : process( rst, clk, req_flag, act_flag ) +variable result_temp : std_logic_vector(32 downto 0); +begin + if (rst = '1') then + multiplier_temp <= (others=>'0'); + result <= (others=>'0'); + count <= (others=>'0'); + act_flag <= '0'; -- default state is inactive + elsif falling_edge( clk ) then + -- + -- start the division if the last division was complete + -- i.e. the active flag was clear + -- and the last byte of the divisor was just written + -- i.e. the request flag was pulsed high for one clock cycle + -- + if (req_flag = '1') and (act_flag = '0') then + multiplier_temp <= multiplier; -- Get Multiplier into temp + result <= (others => '0'); -- Clear the result + count <= (others => '0'); -- Zero the bit counter + act_flag <= '1'; -- Flag multiplication in progress + + elsif ( req_flag = '0' ) and (act_flag = '1') then -- if active flag is set the multiplication must be in progress + + result_temp(32 downto 0) := "0" & result(63 downto 32); + if multiplier_temp(0) = '1' then -- if least significant bit of multiplier is set + result_temp(32 downto 0) := ("0" & result(63 downto 32)) + ("0" & multiplicand); -- add the multiplicand to the msbits of the result + end if; + + -- + -- shift the result down one bit + -- + result(30 downto 0) <= result(31 downto 1); + result(63 downto 31) <= result_temp(32 downto 0); + + -- + -- shift multiplier temp down one bit + -- + multiplier_temp(30 downto 0) <= multiplier_temp(31 downto 1); + multiplier_temp(31) <= '0'; + -- + -- 32 bit multiplication should take 32 clock cycles + -- + count <= count + "00001"; + -- + -- When the count reaches the 31st cycle of the division + -- flag that the multiplication is complete by setting the finish flag. + -- + if count = "11111" then + act_flag <= '0'; -- flag Multiplication complete + end if; + + end if; -- start/finish + end if; -- rst/clk +end process; + +end rtl; +
trunk/rtl/VHDL/mulu32_s2.vhd Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.