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

Subversion Repositories System09

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /System09/trunk/rtl/VHDL
    from Rev 66 to Rev 99
    Reverse comparison

Rev 66 → Rev 99

/spp.vhd
1,155 → 1,175
--===========================================================================----
--
-- S Y N T H E Z I A B L E spp - Simple Parallel Port
--
-- www.OpenCores.Org - September 2003
-- This core adheres to the GNU public license
--
-- File name : spp.vhd
--
-- Purpose : Simple Parallel Port for System09
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
--
-- Uses : None
--
-- Author : John E. Kent
-- dilbert57@opencores.org
--
--===========================================================================----
--
-- Revision History:
--===========================================================================--
--
-- Version 0.1 - 6th Sep 2008
-- Generated from ioport.vhd
--
--===========================================================================
--
-- Parallel printer port pin assignment
--
-- Pin No (DB25) SPP Signal EPP Signal Direction Register Bit Inverted
-- 1 nStrobe Write_n Out Control-0 Yes
-- 2 Data0 Data0 In/Out Data-0 No
-- 3 Data1 Data1 In/Out Data-1 No
-- 4 Data2 Data2 In/Out Data-2 No
-- 5 Data3 Data3 In/Out Data-3 No
-- 6 Data4 Data4 In/Out Data-4 No
-- 7 Data5 Data5 In/Out Data-5 No
-- 8 Data6 Data6 In/Out Data-6 No
-- 9 Data7 Data7 In/Out Data-7 No
-- 10 nAck Interrupt In Status-6 No
-- 11 Busy Wait In Status-7 Yes
-- 12 Paper-Out Spare In Status-5 No
-- 13 Select Spare In Status-4 No
--
-- 14 Linefeed Data_Strobe_n Out Control-1 Yes
-- 15 nError Spare In Status-3 No
-- 16 nInitialize Reset Out Control-2 No
-- 17 nSelect-Printer Addr_Strobe_n Out Control-3 Yes
-- 18-25 Ground Ground - - -
--
-- Address MSB LSB
-- Bit: 7 6 5 4 3 2 1 0
-- Base (SPP Data port) Write Pin: 9 8 7 6 5 4 3 2
-- Base+1 (SPP Status port) Read Pin: ~11 10 12 13 15
-- Base+2 (SPP Control port) Write Pin: ~17 16 ~14 ~1
-- Base+3 (EPP Address port) R/W
-- Base+4 (EPP Data port) R/W
--
-- ~ indicates a hardware inversion of the bit.
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity spp is
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector(2 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
spp_data : out std_logic_vector(7 downto 0);
spp_stat : in std_logic_vector(7 downto 3);
spp_ctrl : out std_logic_vector(3 downto 0);
hold : out std_logic;
irq : out std_logic
);
end;
 
architecture rtl of spp is
 
signal spp_data_reg : std_logic_vector(7 downto 0);
signal spp_stat_reg : std_logic_vector(7 downto 3);
signal spp_ctrl_reg : std_logic_vector(3 downto 0);
 
begin
 
 
--------------------------------
--
-- read I/O port
--
--------------------------------
 
spp_read : process( addr,
spp_data_reg, spp_stat_reg, spp_ctrl_reg,
spp_stat )
begin
spp_stat_reg(6 downto 3) <= spp_stat(6 downto 3);
spp_stat_reg(7) <= not spp_stat(7);
case addr is
when "000" =>
data_out <= spp_data_reg;
 
when "001" =>
data_out <= spp_stat_reg & "000";
 
when "010" =>
data_out <= "0000" & spp_ctrl_reg;
 
when others =>
data_out <= (others=> '0');
end case;
hold <= '0';
irq <= '0';
end process;
 
---------------------------------
--
-- Write I/O ports
--
---------------------------------
 
spp_write : process( clk, rst, addr, cs, rw, data_in,
spp_data_reg, spp_ctrl_reg )
begin
if clk'event and clk = '0' then
if rst = '1' then
spp_data_reg <= "00000000";
spp_ctrl_reg <= "0000";
elsif cs = '1' and rw = '0' then
case addr is
when "000" =>
spp_data_reg <= data_in;
when "010" =>
spp_ctrl_reg <= data_in(3 downto 0);
when others =>
null;
end case;
end if;
end if;
spp_data <= spp_data_reg;
spp_ctrl(0) <= not spp_ctrl_reg(0);
spp_ctrl(1) <= not spp_ctrl_reg(1);
spp_ctrl(2) <= spp_ctrl_reg(2);
spp_ctrl(3) <= not spp_ctrl_reg(3);
end process;
 
end rtl;
--===========================================================================--
-- --
-- Synthesizable Simple Parallel Port --
-- --
--===========================================================================--
--
-- File name : spp.vhd
--
-- Entity name : spp
--
-- Purpose : implements a Simple Parallel Port for System09
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
--
-- Uses : None
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- Description : Register Memory Map
--
-- Address MSB LSB
-- Bit: 7 6 5 4 3 2 1 0
-- Base+$00 (SPP Data port) Write Pin: 9 8 7 6 5 4 3 2
-- Base+$01 (SPP Status port) Read Pin: ~11 10 12 13 15 - - -
-- Base+$02 (SPP Control port) Write Pin: - - - - ~17 16 ~14 ~1
-- Base+$03 (EPP Address port) R/W
-- Base+$04 (EPP Data port) R/W
--
-- ~ indicates a hardware inversion of the bit.
-- Parallel printer port pin assignment
--
-- Pin No (DB25) SPP Signal EPP Signal Direction Register Bit Inverted
-- 1 nStrobe Write_n Out Control-0 Yes
-- 2 Data0 Data0 In/Out Data-0 No
-- 3 Data1 Data1 In/Out Data-1 No
-- 4 Data2 Data2 In/Out Data-2 No
-- 5 Data3 Data3 In/Out Data-3 No
-- 6 Data4 Data4 In/Out Data-4 No
-- 7 Data5 Data5 In/Out Data-5 No
-- 8 Data6 Data6 In/Out Data-6 No
-- 9 Data7 Data7 In/Out Data-7 No
-- 10 nAck Interrupt In Status-6 No
-- 11 Busy Wait In Status-7 Yes
-- 12 Paper-Out Spare In Status-5 No
-- 13 Select Spare In Status-4 No
-- 14 Linefeed Data_Strobe_n Out Control-1 Yes
-- 15 nError Spare In Status-3 No
-- 16 nInitialize Reset Out Control-2 No
-- 17 nSelect-Printer Addr_Strobe_n Out Control-3 Yes
-- 18-25 Ground Ground - - -
--
-- Copyright (C) 2008 - 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 Date Author Description
-- 0.1 2008-09-06 John Kent Initial version generated from ioport.vhd
-- 0.2 2010-08-09 John Kent Updated Header and added GPL
--
--===========================================================================
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity spp is
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector(2 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
spp_data : out std_logic_vector(7 downto 0);
spp_stat : in std_logic_vector(7 downto 3);
spp_ctrl : out std_logic_vector(3 downto 0);
hold : out std_logic;
irq : out std_logic
);
end;
 
architecture rtl of spp is
 
signal spp_data_reg : std_logic_vector(7 downto 0);
signal spp_stat_reg : std_logic_vector(7 downto 3);
signal spp_ctrl_reg : std_logic_vector(3 downto 0);
 
begin
 
 
--------------------------------
--
-- read I/O port
--
--------------------------------
 
spp_read : process( addr,
spp_data_reg, spp_stat_reg, spp_ctrl_reg,
spp_stat )
begin
spp_stat_reg(6 downto 3) <= spp_stat(6 downto 3);
spp_stat_reg(7) <= not spp_stat(7);
case addr is
when "000" =>
data_out <= spp_data_reg;
 
when "001" =>
data_out <= spp_stat_reg & "000";
 
when "010" =>
data_out <= "0000" & spp_ctrl_reg;
 
when others =>
data_out <= (others=> '0');
end case;
hold <= '0';
irq <= '0';
end process;
 
---------------------------------
--
-- Write I/O ports
--
---------------------------------
 
spp_write : process( clk, rst, addr, cs, rw, data_in,
spp_data_reg, spp_ctrl_reg )
begin
if clk'event and clk = '0' then
if rst = '1' then
spp_data_reg <= "00000000";
spp_ctrl_reg <= "0000";
elsif cs = '1' and rw = '0' then
case addr is
when "000" =>
spp_data_reg <= data_in;
when "010" =>
spp_ctrl_reg <= data_in(3 downto 0);
when others =>
null;
end case;
end if;
end if;
spp_data <= spp_data_reg;
spp_ctrl(0) <= not spp_ctrl_reg(0);
spp_ctrl(1) <= not spp_ctrl_reg(1);
spp_ctrl(2) <= spp_ctrl_reg(2);
spp_ctrl(3) <= not spp_ctrl_reg(3);
end process;
 
end rtl;
/trap.vhd
1,288 → 1,306
--===========================================================================--
--
-- S Y N T H E Z I A B L E Timer C O R E
--
-- www.OpenCores.Org - May 2003
-- This core adheres to the GNU public license
--
-- File name : Trap.vhd
--
-- entity name : trap
--
-- Purpose : Implements a 8 bit address and data comparitor module
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
--
-- Author : John E. Kent
--
--===========================================================================----
--
-- Revision History:
--
-- Date: Revision Author
-- 5 May 2003 0.1 John Kent
--
--===========================================================================----
--
-- Register Memory Map
--
-- $00 - Address Comparitor High Byte
-- $01 - Address Comparitor Low byte
-- $02 - Data Comparitor
-- $03 - Control Comparitor
-- $04 - Address Qualifier High Byte
-- $05 - Address Qualifier Low byte
-- $06 - Data Qualifier
-- $07 - Control Qualifier
--
-- Address, Data and Control signals must match in the Comparitor registers
-- Matches are qualified by setting a bit in the Qualifier registers
--
-- Control Comparitor / Qualify (write)
-- b0 - r/w 1=read 0=write
-- b1 - vma 1=valid 0=invalid
-- b7 - irq output 1=match 0=mismatch
--
-- Control Qualifier Read
-- b7 - match flag
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity trap is
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
vma : in std_logic;
addr : in std_logic_vector(15 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
irq : out std_logic
);
end;
 
architecture trap_arch of trap is
 
--
-- Trap registers
--
signal comp_addr_hi : std_logic_vector(7 downto 0);
signal comp_addr_lo : std_logic_vector(7 downto 0);
signal qual_addr_hi : std_logic_vector(7 downto 0);
signal qual_addr_lo : std_logic_vector(7 downto 0);
signal comp_data : std_logic_vector(7 downto 0);
signal qual_data : std_logic_vector(7 downto 0);
signal comp_ctrl : std_logic_vector(7 downto 0);
signal qual_ctrl : std_logic_vector(7 downto 0);
signal match_flag : std_logic;
begin
 
 
--------------------------------
--
-- write control registers
--
--------------------------------
trap_write : process( clk, rst, cs, rw, addr, data_in,
comp_addr_hi, comp_addr_lo, comp_data, comp_ctrl,
qual_addr_hi, qual_addr_lo, qual_data, qual_ctrl )
begin
if clk'event and clk = '0' then
if rst = '1' then
comp_addr_hi <= "00000000";
comp_addr_lo <= "00000000";
comp_data <= "00000000";
comp_ctrl <= "00000000";
qual_addr_hi <= "00000000";
qual_addr_lo <= "00000000";
qual_data <= "00000000";
qual_ctrl <= "00000000";
elsif cs = '1' and rw = '0' then
case addr(2 downto 0) is
when "000" =>
comp_addr_hi <= data_in;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
when "001" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= data_in;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
when "010" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= data_in;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
when "011" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= data_in;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
when "100" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= data_in;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
when "101" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= data_in;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
when "110" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= data_in;
qual_ctrl <= qual_ctrl;
-- when "111" =>
when others =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= data_in;
end case;
else
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
end if;
end if;
end process;
 
--
-- trap data output mux
--
trap_read : process( addr,
comp_addr_hi, comp_addr_lo, comp_data, comp_ctrl,
qual_addr_hi, qual_addr_lo, qual_data, qual_ctrl,
match_flag )
begin
case addr(2 downto 0) is
when "000" =>
data_out <= comp_addr_hi;
when "001" =>
data_out <= comp_addr_lo;
when "010" =>
data_out <= comp_data;
when "011" =>
data_out <= comp_ctrl;
when "100" =>
data_out <= qual_addr_hi;
when "101" =>
data_out <= qual_addr_lo;
when "110" =>
data_out <= qual_data;
-- when "111" =>
when others =>
data_out(6 downto 0) <= qual_ctrl(6 downto 0);
data_out(7) <= match_flag;
end case;
end process;
 
 
--
-- Trap hardware
--
trap_match : process( Clk, rst, cs, rw, addr, vma, match_flag, data_in,
comp_addr_hi, comp_addr_lo, comp_data, comp_ctrl,
qual_addr_hi, qual_addr_lo, qual_data, qual_ctrl)
variable match : std_logic;
variable match_addr_hi : std_logic;
variable match_addr_lo : std_logic;
variable match_data : std_logic;
variable match_ctrl : std_logic;
 
begin
match_addr_hi :=
((comp_addr_hi(7) xor addr(15) ) and qual_addr_hi(7) ) or
((comp_addr_hi(6) xor addr(14) ) and qual_addr_hi(6) ) or
((comp_addr_hi(5) xor addr(13) ) and qual_addr_hi(5) ) or
((comp_addr_hi(4) xor addr(12) ) and qual_addr_hi(4) ) or
((comp_addr_hi(3) xor addr(11) ) and qual_addr_hi(3) ) or
((comp_addr_hi(2) xor addr(10) ) and qual_addr_hi(2) ) or
((comp_addr_hi(1) xor addr( 9) ) and qual_addr_hi(1) ) or
((comp_addr_hi(0) xor addr( 8) ) and qual_addr_hi(0) );
match_addr_lo :=
((comp_addr_lo(7) xor addr( 7) ) and qual_addr_lo(7) ) or
((comp_addr_lo(6) xor addr( 6) ) and qual_addr_lo(6) ) or
((comp_addr_lo(5) xor addr( 5) ) and qual_addr_lo(5) ) or
((comp_addr_lo(4) xor addr( 4) ) and qual_addr_lo(4) ) or
((comp_addr_lo(3) xor addr( 3) ) and qual_addr_lo(3) ) or
((comp_addr_lo(2) xor addr( 2) ) and qual_addr_lo(2) ) or
((comp_addr_lo(1) xor addr( 1) ) and qual_addr_lo(1) ) or
((comp_addr_lo(0) xor addr( 0) ) and qual_addr_lo(0) );
match_data :=
((comp_data(7) xor data_in(7)) and qual_data(7) ) or
((comp_data(6) xor data_in(6)) and qual_data(6) ) or
((comp_data(5) xor data_in(5)) and qual_data(5) ) or
((comp_data(4) xor data_in(4)) and qual_data(4) ) or
((comp_data(3) xor data_in(3)) and qual_data(3) ) or
((comp_data(2) xor data_in(2)) and qual_data(2) ) or
((comp_data(1) xor data_in(1)) and qual_data(1) ) or
((comp_data(0) xor data_in(0)) and qual_data(0) );
match_ctrl :=
((comp_ctrl(0) xor rw ) and qual_ctrl(0) ) or
((comp_ctrl(1) xor vma ) and qual_ctrl(1) );
 
match := not ( match_addr_hi or match_addr_lo or match_data or match_ctrl);
 
if clk'event and clk = '0' then
if rst = '1' then
match_flag <= '0';
elsif cs = '1' and rw = '0' then
match_flag <= '0';
else
if match = comp_ctrl(7) then
match_flag <= '1';
else
match_flag <= match_flag;
end if;
 
end if;
end if;
irq <= match_flag and qual_ctrl(7);
end process;
 
end trap_arch;
--===========================================================================--
-- --
-- Synthesizable Hardware Breakpoint Trap --
-- --
--===========================================================================--
--
-- File name : trap.vhd
--
-- Entity name : trap
--
-- Purpose : Implements a 8 bit address and data hardware breakpoint comparator
-- which generates an interrupt output on qualified match conditions
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- Description : Register Memory Map
--
-- Base + $00 - Address Comparitor High Byte
-- Base + $01 - Address Comparitor Low byte
-- Base + $02 - Data Comparitor
-- Base + $03 - Control Comparitor
-- Base + $04 - Address Qualifier High Byte
-- Base + $05 - Address Qualifier Low byte
-- Base + $06 - Data Qualifier
-- Base + $07 - Control Qualifier
--
-- Address, Data and Control signals
-- must match in the Comparitor registers
-- Matches are qualified by setting a bit
-- in the Qualifier registers
--
-- Control Comparitor / Control Qualify (write)
-- b0 - r/w 1=read 0=write
-- b1 - vma 1=valid 0=invalid
-- b7 - irq output 1=match 0=mismatch
--
-- Control Qualifier Read
-- b7 - match flag
--
-- 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 Author Date Description
-- 0.1 John Kent 2003-05-05 Initial version
-- 0.2 John kent 2010-08-09 Updated header & GPL information
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity trap is
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
vma : in std_logic;
addr : in std_logic_vector(15 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
irq : out std_logic
);
end;
 
architecture trap_arch of trap is
 
--
-- Trap registers
--
signal comp_addr_hi : std_logic_vector(7 downto 0);
signal comp_addr_lo : std_logic_vector(7 downto 0);
signal qual_addr_hi : std_logic_vector(7 downto 0);
signal qual_addr_lo : std_logic_vector(7 downto 0);
signal comp_data : std_logic_vector(7 downto 0);
signal qual_data : std_logic_vector(7 downto 0);
signal comp_ctrl : std_logic_vector(7 downto 0);
signal qual_ctrl : std_logic_vector(7 downto 0);
signal match_flag : std_logic;
begin
 
 
--------------------------------
--
-- write control registers
--
--------------------------------
trap_write : process( clk, rst, cs, rw, addr, data_in,
comp_addr_hi, comp_addr_lo, comp_data, comp_ctrl,
qual_addr_hi, qual_addr_lo, qual_data, qual_ctrl )
begin
if clk'event and clk = '0' then
if rst = '1' then
comp_addr_hi <= "00000000";
comp_addr_lo <= "00000000";
comp_data <= "00000000";
comp_ctrl <= "00000000";
qual_addr_hi <= "00000000";
qual_addr_lo <= "00000000";
qual_data <= "00000000";
qual_ctrl <= "00000000";
elsif cs = '1' and rw = '0' then
case addr(2 downto 0) is
when "000" =>
comp_addr_hi <= data_in;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
when "001" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= data_in;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
when "010" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= data_in;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
when "011" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= data_in;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
when "100" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= data_in;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
when "101" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= data_in;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
when "110" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= data_in;
qual_ctrl <= qual_ctrl;
-- when "111" =>
when others =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= data_in;
end case;
else
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
end if;
end if;
end process;
 
--
-- trap data output mux
--
trap_read : process( addr,
comp_addr_hi, comp_addr_lo, comp_data, comp_ctrl,
qual_addr_hi, qual_addr_lo, qual_data, qual_ctrl,
match_flag )
begin
case addr(2 downto 0) is
when "000" =>
data_out <= comp_addr_hi;
when "001" =>
data_out <= comp_addr_lo;
when "010" =>
data_out <= comp_data;
when "011" =>
data_out <= comp_ctrl;
when "100" =>
data_out <= qual_addr_hi;
when "101" =>
data_out <= qual_addr_lo;
when "110" =>
data_out <= qual_data;
-- when "111" =>
when others =>
data_out(6 downto 0) <= qual_ctrl(6 downto 0);
data_out(7) <= match_flag;
end case;
end process;
 
 
--
-- Trap hardware
--
trap_match : process( Clk, rst, cs, rw, addr, vma, match_flag, data_in,
comp_addr_hi, comp_addr_lo, comp_data, comp_ctrl,
qual_addr_hi, qual_addr_lo, qual_data, qual_ctrl)
variable match : std_logic;
variable match_addr_hi : std_logic;
variable match_addr_lo : std_logic;
variable match_data : std_logic;
variable match_ctrl : std_logic;
 
begin
match_addr_hi :=
((comp_addr_hi(7) xor addr(15) ) and qual_addr_hi(7) ) or
((comp_addr_hi(6) xor addr(14) ) and qual_addr_hi(6) ) or
((comp_addr_hi(5) xor addr(13) ) and qual_addr_hi(5) ) or
((comp_addr_hi(4) xor addr(12) ) and qual_addr_hi(4) ) or
((comp_addr_hi(3) xor addr(11) ) and qual_addr_hi(3) ) or
((comp_addr_hi(2) xor addr(10) ) and qual_addr_hi(2) ) or
((comp_addr_hi(1) xor addr( 9) ) and qual_addr_hi(1) ) or
((comp_addr_hi(0) xor addr( 8) ) and qual_addr_hi(0) );
match_addr_lo :=
((comp_addr_lo(7) xor addr( 7) ) and qual_addr_lo(7) ) or
((comp_addr_lo(6) xor addr( 6) ) and qual_addr_lo(6) ) or
((comp_addr_lo(5) xor addr( 5) ) and qual_addr_lo(5) ) or
((comp_addr_lo(4) xor addr( 4) ) and qual_addr_lo(4) ) or
((comp_addr_lo(3) xor addr( 3) ) and qual_addr_lo(3) ) or
((comp_addr_lo(2) xor addr( 2) ) and qual_addr_lo(2) ) or
((comp_addr_lo(1) xor addr( 1) ) and qual_addr_lo(1) ) or
((comp_addr_lo(0) xor addr( 0) ) and qual_addr_lo(0) );
match_data :=
((comp_data(7) xor data_in(7)) and qual_data(7) ) or
((comp_data(6) xor data_in(6)) and qual_data(6) ) or
((comp_data(5) xor data_in(5)) and qual_data(5) ) or
((comp_data(4) xor data_in(4)) and qual_data(4) ) or
((comp_data(3) xor data_in(3)) and qual_data(3) ) or
((comp_data(2) xor data_in(2)) and qual_data(2) ) or
((comp_data(1) xor data_in(1)) and qual_data(1) ) or
((comp_data(0) xor data_in(0)) and qual_data(0) );
match_ctrl :=
((comp_ctrl(0) xor rw ) and qual_ctrl(0) ) or
((comp_ctrl(1) xor vma ) and qual_ctrl(1) );
 
match := not ( match_addr_hi or match_addr_lo or match_data or match_ctrl);
 
if rst = '1' then
match_flag <= '0';
elsif clk'event and clk = '0' then
if cs = '1' and rw = '0' then
match_flag <= '0';
else
if match = comp_ctrl(7) then
match_flag <= '1';
end if;
end if;
end if;
irq <= match_flag and qual_ctrl(7);
end process;
 
end trap_arch;
/ACIA_Clock.vhd
1,43 → 1,59
-----------------------------------------------------------------
--===========================================================================--
-- --
-- ACIA_Clock.vhd - Synthesizable Baud Rate Clock Divider --
-- --
--===========================================================================--
--
-- ACIA Clock Divider for System09
-- File name : ACIA_Clock.vhd
--
-----------------------------------------------------------------
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
 
package bit_funcs is
function log2(v: in natural) return natural;
end package bit_funcs;
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
 
package body bit_funcs is
function log2(v: in natural) return natural is
variable n: natural;
variable logn: natural;
begin
n := 1;
for i in 0 to 128 loop
logn := i;
exit when (n>=v);
n := n * 2;
end loop;
return logn;
end function log2;
 
end package body bit_funcs;
 
-- Purpose : Implements a baud rate clock divider for a 6850 compatible
-- Asynchronous Communications Interface Adapter
--
-- Dependencies : ieee.std_logic_1164
-- ieee.std_logic_arith
-- ieee.std_logic_unsigned
-- ieee.numeric_std
-- unisim.vcomponents
-- work.bit_funcs
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- ACIA_Clock.vhd is baud rate clock divider for a 6850 compatible ACIA core.
--
-- 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 --
-- --
--===========================================================================--
--
-- Revision Name Date Description
-- 0.1 John Kent unknown Initial version
-- 1.0 John Kent 30th May 2010 Added GPL header
--
 
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
library unisim;
use unisim.vcomponents.all;
44,16 → 60,16
library work;
use work.bit_funcs.all;
 
entity ACIA_Clock is
entity acia_clock is
generic (
SYS_Clock_Frequency : integer;
ACIA_Clock_Frequency : integer
SYS_CLK_FREQ : integer;
ACIA_CLK_FREQ : integer
);
port(
clk : in Std_Logic; -- System Clock input
ACIA_Clk : out Std_Logic -- ACIA Clock output
acia_clk : out Std_Logic -- ACIA Clock output
);
end ACIA_Clock;
end acia_clock;
 
-------------------------------------------------------------------------------
-- Architecture for ACIA_Clock
60,9 → 76,9
-------------------------------------------------------------------------------
architecture rtl of ACIA_Clock is
 
constant FULL_CYCLE : integer := (SYS_Clock_Frequency / ACIA_Clock_Frequency);
constant FULL_CYCLE : integer := (SYS_CLK_FREQ / ACIA_CLK_FREQ);
constant HALF_CYCLE : integer := (FULL_CYCLE / 2);
signal ACIA_Count : Std_Logic_Vector(log2(FULL_CYCLE) downto 0) := (Others => '0');
signal acia_count : Std_Logic_Vector(log2(FULL_CYCLE) downto 0) := (Others => '0');
 
begin
--
71,18 → 87,17
-- 25MHz / 27 = 926,000 KHz = 57,870Bd * 16
-- 50MHz / 54 = 926,000 KHz = 57,870Bd * 16
--
--my_ACIA_clock: process( clk, ACIA_Count )
my_ACIA_clock: process( clk )
my_acia_clock: process( clk )
begin
if(clk'event and clk = '0') then
if( ACIA_Count = (FULL_CYCLE - 1) ) then
ACIA_Clk <= '0';
ACIA_Count <= (others => '0'); --"000000";
if( acia_count = (FULL_CYCLE - 1) ) then
acia_clk <= '0';
acia_count <= (others => '0'); --"000000";
else
if( ACIA_Count = (HALF_CYCLE - 1) ) then
ACIA_Clk <='1';
if( acia_count = (HALF_CYCLE - 1) ) then
acia_clk <='1';
end if;
ACIA_Count <= ACIA_Count + 1;
acia_count <= acia_count + 1;
end if;
end if;
end process;
/datram.vhd
1,63 → 1,89
--===========================================================================--
--===========================================================================--
-- --
-- Synthesizable SWTPc 6809 Dynamic Address Translation Table --
-- --
--===========================================================================--
--
-- S Y N T H E Z I A B L E Dynamic Address Translation Registers
-- File name : datram.vhd
--
-- Entity name : dat_ram
--
-- www.OpenCores.Org - December 2002
-- This core adheres to the GNU public license
--
-- File name : datram.vhd
--
-- entity name : dat_ram
--
-- Purpose : Implements a Dynamic Address Translation RAM module
-- Maps the high order 4 address bits to 8 address lines
-- extending the memory addressing range to 1 Mbytes
-- Memory segments are mapped on 4 KByte boundaries
-- The DAT registers map to the top of memory
-- ($FFF0 - $FFFF) and are write only so can map behind ROM.
-- Since the DAT is not supported by SWTBUG for the 6800,
-- the resgisters reset state map the bottom 64K of RAM.
-- Purpose : Implements a Dynamic Address Translation RAM module
-- as found in the SWTPc MP-09 CPU card.
-- Maps the high order 4 address bits to 8 address lines
-- extending the memory addressing range from 64K to 1MByte
-- Memory segments are mapped on 4 KByte boundaries
-- The DAT registers are mapped at the the top of memory
-- ($FFF0 - $FFFF) and are write only so can map behind ROM.
-- Since the DAT is not supported by SWTBUG for the 6800,
-- the resgisters reset state map the bottom 64K of RAM.
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
-- 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
--
-- Description :
--
-- DAT is initializedas follows:
--
-- Author : John E. Kent
-- DAT Dat Logical Physical
-- Reg Val Addr Addr
-- fff0 - 0f - page 0 - $0xxx = $00xxx (RAM)
-- fff1 - 0e - page 1 - $1xxx = $01xxx (RAM)
-- fff2 - 0d - page 0 - $2xxx = $02xxx (RAM)
-- fff3 - 0c - page 0 - $3xxx = $03xxx (RAM)
-- fff4 - 0b - page 0 - $4xxx = $04xxx (RAM)
-- fff5 - 0a - page 0 - $5xxx = $05xxx (RAM)
-- fff6 - 09 - page 0 - $6xxx = $06xxx (RAM)
-- fff7 - 08 - page 0 - $7xxx = $07xxx (RAM)
-- fff8 - 07 - page 0 - $8xxx = $08xxx (RAM)
-- fff9 - 06 - page 0 - $9xxx = $09xxx (RAM)
-- fffa - 05 - page 0 - $axxx = $0axxx (RAM)
-- fffb - 04 - page 0 - $bxxx = $0bxxx (RAM)
-- fffc - 03 - page 0 - $cxxx = $0cxxx (RAM)
-- fffd - 02 - page 0 - $dxxx = $0dxxx (RAM)
-- fffe - f1 - page 0 - $exxx = $fexxx (I/O)
-- ffff - f0 - page 0 - $fxxx = $ffxxx (ROM/DMFA2)
--
-- 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 Date Author Changes
--
-- 0.1 2002-11-10 John Kent Initial version
--
--===========================================================================----
-- 0.2 2006-11-21 John Kent Inverted bottom 4 bits of dat_addr
-- so that it is compatible with SWTPc MP-09 card.
--
-- Revision History:
-- 0.3 2007-02-25 John Kent Modify the sensitivity lists
--
-- 0.4 2010-06-17 John Kent Update header and added GPL
--
-- Date Revision Author
-- 10 Nov 2002 0.1 John Kent
--
-- 21 Nov 2006 0.2 John Kent
-- Inverted bottom 4 bits of dat_addr
-- so that it is compatible with SWTPc MP-09 card.
-- DAT is initializedas follows:
--
-- DAT Dat Logical Physical
-- Reg Val Addr Addr
-- fff0 - 0f - page 0 - $0xxx = $00xxx (RAM)
-- fff1 - 0e - page 1 - $1xxx = $01xxx (RAM)
-- fff2 - 0d - page 0 - $2xxx = $02xxx (RAM)
-- fff3 - 0c - page 0 - $3xxx = $03xxx (RAM)
-- fff4 - 0b - page 0 - $4xxx = $04xxx (RAM)
-- fff5 - 0a - page 0 - $5xxx = $05xxx (RAM)
-- fff6 - 09 - page 0 - $6xxx = $06xxx (RAM)
-- fff7 - 08 - page 0 - $7xxx = $07xxx (RAM)
-- fff8 - 07 - page 0 - $8xxx = $08xxx (RAM)
-- fff9 - 06 - page 0 - $9xxx = $09xxx (RAM)
-- fffa - 05 - page 0 - $axxx = $0axxx (RAM)
-- fffb - 04 - page 0 - $bxxx = $0bxxx (RAM)
-- fffc - 03 - page 0 - $cxxx = $0cxxx (RAM)
-- fffd - 02 - page 0 - $dxxx = $0dxxx (RAM)
-- fffe - f1 - page 0 - $exxx = $fexxx (I/O)
-- ffff - f0 - page 0 - $fxxx = $ffxxx (ROM/DMFA2)
 
-- 25 Feb 2007 0.3 John Kent
-- modify the sensitivity lists
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
69,24 → 95,24
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr_hi : in std_logic_vector(3 downto 0);
addr_lo : in std_logic_vector(3 downto 0);
rw : in std_logic;
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0));
end dat_ram;
 
architecture rtl of dat_ram is
signal dat_reg0 : std_logic_vector(7 downto 0);
signal dat_reg1 : std_logic_vector(7 downto 0);
signal dat_reg2 : std_logic_vector(7 downto 0);
signal dat_reg3 : std_logic_vector(7 downto 0);
signal dat_reg4 : std_logic_vector(7 downto 0);
signal dat_reg5 : std_logic_vector(7 downto 0);
signal dat_reg6 : std_logic_vector(7 downto 0);
signal dat_reg7 : std_logic_vector(7 downto 0);
signal dat_reg8 : std_logic_vector(7 downto 0);
signal dat_reg9 : std_logic_vector(7 downto 0);
signal dat_reg0 : std_logic_vector(7 downto 0);
signal dat_reg1 : std_logic_vector(7 downto 0);
signal dat_reg2 : std_logic_vector(7 downto 0);
signal dat_reg3 : std_logic_vector(7 downto 0);
signal dat_reg4 : std_logic_vector(7 downto 0);
signal dat_reg5 : std_logic_vector(7 downto 0);
signal dat_reg6 : std_logic_vector(7 downto 0);
signal dat_reg7 : std_logic_vector(7 downto 0);
signal dat_reg8 : std_logic_vector(7 downto 0);
signal dat_reg9 : std_logic_vector(7 downto 0);
signal dat_reg10 : std_logic_vector(7 downto 0);
signal dat_reg11 : std_logic_vector(7 downto 0);
signal dat_reg12 : std_logic_vector(7 downto 0);
/timer.vhd
1,63 → 1,86
--===========================================================================----
--===========================================================================--
-- --
-- Synthesizable 8 bit Timer --
-- --
--===========================================================================--
--
-- S Y N T H E Z I A B L E timer - 9 bit timer
-- File name : timer.vhd
--
-- Entity name : timer
--
-- www.OpenCores.Org - September 2003
-- This core adheres to the GNU public license
-- Purpose : 8 bit timer module for System09
--
-- File name : timer.vhd
-- Dependencies : ieee.std_logic_1164
-- ieee.std_logic_unsigned
--
-- Purpose : 8 bit timer module for System 09
-- Uses : None
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
-- Author : John E. Kent
--
-- Uses : None
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- Registers :
--
-- IO address + 0 Read - Down Count register
-- Bits[7..0] = Counter Value
--
-- IO address + 0 Write - Preset Count register
-- Bits[7..0] = Preset Value
--
-- Author : John E. Kent
-- dilbert57@opencores.org
-- IO address + 1 Read - Status register
-- Bit[7] = Interrupt Flag
-- Bits[6..0] = undefined
--
--===========================================================================----
-- IO address + 1 Write - Control register
-- Bit[7] = Interrupt Enable
-- Bits[6..1] = Unedfined
-- Bit[0] = Counter enable
--
-- Revision History:
--===========================================================================--
-- Operation :
--
-- Version 0.1 - 6 Sept 2002 - John Kent
-- converted to a single timer
-- made syncronous with system clock
-- Write count to counter register
-- Enable counter by setting bit 0 of the control register
-- Enable interrupts by setting bit 7 of the control register
-- Counter will count down to zero
-- When it reaches zero the terminal flag is set
-- If the interrupt is enabled an interrupt is generated
-- The interrupt may be disabled by writing a 0 to bit 7
-- of the control register or by loading a new down count
-- into the counter register.
--
-- Copyright (C) 2002 - 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 Date Author Changes
--
-- 0.1 2002-09-06 John Kent Converted to a single timer
-- Made synchronous with system clock
-- 1.0 2003-09-06 John Kent Changed Clock Edge
-- Released to opencores.org
-- 2.0 2008-02-05 John Kent Removed Timer inputs and outputs
-- Made into a simple 8 bit interrupt down counter
-- 2.1 2010-06-17 John Kent Updated header and added GPL
--
-- Version 1.0 - 6 Sept 2003 - John Kent
-- Realeased to open Cores
-- changed Clock Edge
--
-- Version 2.0 - 5th February 2008 - John Kent
-- removed Timer inputs and outputs
-- made into a simple 8 bit interrupt down counter
--
--===========================================================================
--
-- Register Addressing:
-- addr=0 rw=1 down count
-- addr=0 rw=0 preset count
-- addr=1 rw=1 status
-- addr=1 rw=0 control
--
-- Control register
-- b0 = counter enable
-- b7 = interrupt enable
--
-- Status register
-- b7 = interrupt flag
--
-- Operation:
-- Write count to counter register
-- Enable counter by setting bit 0 of the control register
-- enable interrupts by setting bit 7 of the control register
-- Counter will count down to zero
-- when it reaches zero the terminal flag is set
-- if the interrupt is enabled an interrupt is generated
-- The interrupt may be disabled by writing a 0 to bit 7 of the control register
-- or by loading a new down count into the counter register.
--
library ieee;
use ieee.std_logic_1164.all;
68,8 → 91,8
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
addr : in std_logic;
rw : in std_logic;
addr : in std_logic;
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
irq : out std_logic
84,64 → 107,43
--
-- control/status register bits
--
constant T_enab : integer := 0; -- 0=disable, 1=enabled
constant T_irq : integer := 7; -- 0=disabled, 1-enabled
constant BIT_ENB : integer := 0; -- 0=disable, 1=enabled
constant BIT_IRQ : integer := 7; -- 0=disabled, 1-enabled
 
begin
 
--------------------------------
--
-- write control registers
-- doesn't do anything yet
--
--------------------------------
timer_write : process( clk, rst, cs, rw, addr, data_in,
timer_ctrl, timer_term, timer_count )
begin
if rst = '1' then
timer_count <= "00000000";
timer_ctrl <= "00000000";
timer_term <= '0';
elsif clk'event and clk = '0' then
if cs = '1' and rw = '0' then
if addr='0' then
timer_count <= data_in;
--------------------------------
--
-- write control registers
--
--------------------------------
timer_control : process( clk, rst, cs, rw, addr, data_in,
timer_ctrl, timer_term, timer_count )
begin
if clk'event and clk = '0' then
if rst = '1' then
timer_count <= (others=>'0');
timer_ctrl <= (others=>'0');
timer_term <= '0';
elsif cs = '1' and rw = '0' then
if addr='0' then
timer_count <= data_in;
timer_term <= '0';
else
timer_ctrl <= data_in;
end if;
else
timer_ctrl <= data_in;
end if;
else
if (timer_ctrl(T_enab) = '1') then
if (timer_count = "00000000" ) then
timer_term <= '1';
else
timer_count <= timer_count - 1;
if (timer_ctrl(BIT_ENB) = '1') then
if (timer_count = "00000000" ) then
timer_term <= '1';
else
timer_count <= timer_count - 1;
end if;
end if;
end if;
end if;
end if;
end if;
end process;
 
--
-- timer data output mux
--
timer_read : process( addr, timer_count, timer_stat )
begin
if addr='0' then
data_out <= timer_count;
else
data_out <= timer_stat;
end if;
end process;
 
--
-- read timer strobe to reset interrupts
--
timer_interrupt : process( timer_term, timer_ctrl )
begin
irq <= timer_term and timer_ctrl( T_irq );
end process;
 
end process;
 
--
-- timer status register
--
148,8 → 150,28
timer_status : process( timer_ctrl, timer_term )
begin
timer_stat(6 downto 0) <= timer_ctrl(6 downto 0);
timer_stat(T_irq) <= timer_term;
timer_stat(BIT_IRQ) <= timer_term;
end process;
 
--
-- timer data output mux
--
timer_data_out : process( addr, timer_count, timer_stat )
begin
if addr = '0' then
data_out <= timer_count;
else
data_out <= timer_stat;
end if;
end process;
 
--
-- read timer strobe to reset interrupts
--
timer_interrupt : process( timer_term, timer_ctrl )
begin
irq <= timer_term and timer_ctrl(BIT_IRQ);
end process;
 
end rtl;
/spi-master.vhd
1,245 → 1,317
-- SPI bus master for System09 (http://members.optushome.com.au/jekent/system09/index.html)
 
-- This core implements a SPI master interface. Transfer size is 4, 8, 12 or
-- 16 bits. The SPI clock is 0 when idle, sampled on the rising edge of the SPI
-- clock. The SPI clock is derived from the bus clock input divided
-- by 2, 4, 8 or 16.
 
-- clk, reset, cs, rw, addr, data_in, data_out and irq represent the System09
-- bus interface.
-- spi_clk, spi_mosi, spi_miso and spi_cs_n are the standard SPI signals meant
-- to be routed off-chip.
 
-- The SPI core provides for four register addresses that the CPU can read or
-- write:
 
-- 0 -> DL: Data LSB
-- 1 -> DH: Data MSB
-- 2 -> CS: Command/Status
-- 3 -> CO: Config
 
-- Write bits, CS:
--
-- START CS[0]: Start transfer
-- END CS[1]: Deselect device after transfer (or immediately if START = '0')
-- IRQEN CS[2]: Generate IRQ at end of transfer
-- SPIAD CS[6:4]: SPI device address
--
-- Read bits, CS:
--
-- BUSY CS[0]: Currently transmitting data
--
-- Write BITS, CO:
--
-- DIVIDE CO[1:0]: SPI clock divisor, 00=clk/2, 01=clk/4, 10=clk/8, 11=clk/16
-- LENGTH CO[3:2]: Transfer length, 00=4 bits, 01=8 bits, 10=12 bits, 11=16 bits
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity spi_master is
port (
clk, reset, cs, rw : in std_logic;
addr : in std_logic_vector(1 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
irq : out std_logic;
spi_clk, spi_mosi : out std_logic;
spi_cs_n : out std_logic_vector(7 downto 0);
spi_miso : in std_logic);
end;
 
architecture rtl of spi_master is
 
-- State type of the SPI transfer state machine
type state_type is (s_idle, s_running);
signal state : state_type;
-- Shift register
signal shift_reg : std_logic_vector(15 downto 0);
-- Buffer to hold data to be sent
signal spi_data_buf : std_logic_vector(15 downto 0);
-- Start transmission flag
signal start : std_logic;
-- Number of bits transfered
signal count : std_logic_vector(3 downto 0);
-- Buffered SPI clock
signal spi_clk_buf : std_logic;
-- Buffered SPI clock output
signal spi_clk_out : std_logic;
-- Previous SPI clock state
signal prev_spi_clk : std_logic;
-- Number of clk cycles-1 in this SPI clock period
signal spi_clk_count : std_logic_vector(2 downto 0);
-- SPI clock divisor
signal spi_clk_divide : std_logic_vector(1 downto 0);
-- SPI transfer length
signal transfer_length : std_logic_vector(1 downto 0);
-- Flag to indicate that the SPI slave should be deselected after the current
-- transfer
signal deselect : std_logic;
-- Flag to indicate that an IRQ should be generated at the end of a transfer
signal irq_enable : std_logic;
-- Internal chip select signal, will be demultiplexed through the cs_mux
signal spi_cs : std_logic;
-- Current SPI device address
signal spi_addr : std_logic_vector(2 downto 0);
begin
 
-- Read CPU bus into internal registers
cpu_write : process(clk, reset)
begin
if reset = '1' then
deselect <= '0';
irq_enable <= '0';
start <= '0';
spi_clk_divide <= "11";
transfer_length <= "11";
spi_data_buf <= (others => '0');
elsif falling_edge(clk) then
start <= '0';
if cs = '1' and rw = '0' then
case addr is
when "00" =>
spi_data_buf(7 downto 0) <= data_in;
when "01" =>
spi_data_buf(15 downto 8) <= data_in;
when "10" =>
start <= data_in(0);
deselect <= data_in(1);
irq_enable <= data_in(2);
spi_addr <= data_in(6 downto 4);
when "11" =>
spi_clk_divide <= data_in(1 downto 0);
transfer_length <= data_in(3 downto 2);
when others =>
null;
end case;
end if;
end if;
end process;
 
-- Provide data for the CPU to read
cpu_read : process(shift_reg, addr, state, deselect, start)
begin
data_out <= (others => '0');
case addr is
when "00" =>
data_out <= shift_reg(7 downto 0);
when "01" =>
data_out <= shift_reg(15 downto 8);
when "10" =>
if state = s_idle then
data_out(0) <= '0';
else
data_out(0) <= '1';
end if;
data_out(1) <= deselect;
when others =>
null;
end case;
end process;
 
spi_cs_n <= "11111110" when spi_addr = "000" and spi_cs = '1' else
"11111101" when spi_addr = "001" and spi_cs = '1' else
"11111011" when spi_addr = "010" and spi_cs = '1' else
"11110111" when spi_addr = "011" and spi_cs = '1' else
"11101111" when spi_addr = "100" and spi_cs = '1' else
"11011111" when spi_addr = "101" and spi_cs = '1' else
"10111111" when spi_addr = "110" and spi_cs = '1' else
"01111111" when spi_addr = "111" and spi_cs = '1' else
"11111111";
 
-- SPI transfer state machine
spi_proc : process(clk, reset)
begin
if reset = '1' then
count <= (others => '0');
shift_reg <= (others => '0');
prev_spi_clk <= '0';
spi_clk_out <= '0';
spi_cs <= '0';
state <= s_idle;
irq <= 'Z';
elsif falling_edge(clk) then
prev_spi_clk <= spi_clk_buf;
irq <= 'Z';
case state is
when s_idle =>
if start = '1' then
count <= (others => '0');
shift_reg <= spi_data_buf;
spi_cs <= '1';
state <= s_running;
elsif deselect = '1' then
spi_cs <= '0';
end if;
when s_running =>
if prev_spi_clk = '1' and spi_clk_buf = '0' then
spi_clk_out <= '0';
count <= count + "0001";
shift_reg <= shift_reg(14 downto 0) & spi_miso;
if ((count = "0011" and transfer_length = "00")
or (count = "0111" and transfer_length = "01")
or (count = "1011" and transfer_length = "10")
or (count = "1111" and transfer_length = "11")) then
if deselect = '1' then
spi_cs <= '0';
end if;
if irq_enable = '1' then
irq <= '1';
end if;
state <= s_idle;
end if;
elsif prev_spi_clk = '0' and spi_clk_buf = '1' then
spi_clk_out <= '1';
end if;
when others =>
null;
end case;
end if;
end process;
 
-- Generate SPI clock
spi_clock_gen : process(clk, reset)
begin
if reset = '1' then
spi_clk_count <= (others => '0');
spi_clk_buf <= '0';
elsif falling_edge(clk) then
if state = s_running then
if ((spi_clk_divide = "00")
or (spi_clk_divide = "01" and spi_clk_count = "001")
or (spi_clk_divide = "10" and spi_clk_count = "011")
or (spi_clk_divide = "11" and spi_clk_count = "111")) then
spi_clk_buf <= not spi_clk_buf;
spi_clk_count <= (others => '0');
else
spi_clk_count <= spi_clk_count + "001";
end if;
else
spi_clk_buf <= '0';
end if;
end if;
end process;
 
spi_mosi_mux : process(shift_reg, transfer_length)
begin
case transfer_length is
when "00" =>
spi_mosi <= shift_reg(3);
when "01" =>
spi_mosi <= shift_reg(7);
when "10" =>
spi_mosi <= shift_reg(11);
when "11" =>
spi_mosi <= shift_reg(15);
when others =>
null;
end case;
end process;
spi_clk <= spi_clk_out;
 
end rtl;
--===========================================================================--
-- --
-- Synthesizable Serial Peripheral Interface Master --
-- --
--===========================================================================--
--
-- File name : spi-master.vhd
--
-- Entity name : spi-master
--
-- Purpose : Implements a SPI Master Controller
--
-- Dependencies : ieee.std_logic_1164
-- ieee.std_logic_arith
-- ieee.std_logic_unsigned
-- ieee.numeric_std
-- unisim.vcomponents
--
-- Author : Hans Huebner
--
-- Email : hans@huebner.org
--
-- Web : http://opencores.org/project,system09
--
-- Description : This core implements a SPI master interface.
-- Transfer size is 4, 8, 12 or 16 bits.
-- The SPI clock is 0 when idle, sampled on
-- the rising edge of the SPI clock.
-- The SPI clock is derived from the bus clock input
-- divided by 2, 4, 8 or 16.
--
-- clk, reset, cs, rw, addr, data_in, data_out and irq
-- represent the System09 bus interface.
-- spi_clk, spi_mosi, spi_miso and spi_cs_n are the
-- standard SPI signals meant to be routed off-chip.
--
-- The SPI core provides for four register addresses
-- that the CPU can read or writen to:
--
-- Base + $00 -> DL: Data Low LSB
-- Base + $01 -> DH: Data High MSB
-- Base + $02 -> CS: Command/Status
-- Base + $03 -> CO: Config
--
-- CS: Write bits:
--
-- CS[0] START : Start transfer
-- CS[1] END : Deselect device after transfer
-- (or immediately if START = '0')
-- CS[2] IRQEN : Generate IRQ at end of transfer
-- CS[6:4] SPIAD : SPI device address
--
-- CS: Read bits
--
-- CS[0] BUSY : Currently transmitting data
--
-- CO: Write bits
--
-- CO[1:0] DIVIDE: SPI clock divisor,
-- 00=clk/2,
-- 01=clk/4,
-- 10=clk/8,
-- 11=clk/16
-- CO[3:2] LENGTH: Transfer length,
-- 00= 4 bits,
-- 01= 8 bits,
-- 10=12 bits,
-- 11=16 bits
--
-- Copyright (C) 2009 - 2010 Hans Huebner
--
-- 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 Author Date Description
--
-- 0.1 Hans Huebner 23 February 2009 SPI bus master for System09
-- 0.2 John Kent 16 June 2010 Added GPL notice
--
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity spi_master is
port (
--
-- CPU Interface Signals
--
clk : in std_logic;
reset : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector(1 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
irq : out std_logic;
--
-- SPI Interface Signals
--
spi_miso : in std_logic;
spi_mosi : out std_logic;
spi_clk : out std_logic;
spi_cs_n : out std_logic_vector(7 downto 0)
);
end;
 
architecture rtl of spi_master is
 
-- State type of the SPI transfer state machine
type state_type is (s_idle, s_running);
signal state : state_type;
-- Shift register
signal shift_reg : std_logic_vector(15 downto 0);
-- Buffer to hold data to be sent
signal spi_data_buf : std_logic_vector(15 downto 0);
-- Start transmission flag
signal start : std_logic;
-- Number of bits transfered
signal count : std_logic_vector(3 downto 0);
-- Buffered SPI clock
signal spi_clk_buf : std_logic;
-- Buffered SPI clock output
signal spi_clk_out : std_logic;
-- Previous SPI clock state
signal prev_spi_clk : std_logic;
-- Number of clk cycles-1 in this SPI clock period
signal spi_clk_count : std_logic_vector(2 downto 0);
-- SPI clock divisor
signal spi_clk_divide : std_logic_vector(1 downto 0);
-- SPI transfer length
signal transfer_length : std_logic_vector(1 downto 0);
-- Flag to indicate that the SPI slave should be deselected after the current
-- transfer
signal deselect : std_logic;
-- Flag to indicate that an IRQ should be generated at the end of a transfer
signal irq_enable : std_logic;
-- Internal chip select signal, will be demultiplexed through the cs_mux
signal spi_cs : std_logic;
-- Current SPI device address
signal spi_addr : std_logic_vector(2 downto 0);
begin
 
-- Read CPU bus into internal registers
cpu_write : process(clk, reset)
begin
if reset = '1' then
deselect <= '0';
irq_enable <= '0';
start <= '0';
spi_clk_divide <= "11";
transfer_length <= "11";
spi_data_buf <= (others => '0');
elsif falling_edge(clk) then
start <= '0';
if cs = '1' and rw = '0' then
case addr is
when "00" =>
spi_data_buf(7 downto 0) <= data_in;
when "01" =>
spi_data_buf(15 downto 8) <= data_in;
when "10" =>
start <= data_in(0);
deselect <= data_in(1);
irq_enable <= data_in(2);
spi_addr <= data_in(6 downto 4);
when "11" =>
spi_clk_divide <= data_in(1 downto 0);
transfer_length <= data_in(3 downto 2);
when others =>
null;
end case;
end if;
end if;
end process;
 
-- Provide data for the CPU to read
cpu_read : process(shift_reg, addr, state, deselect, start)
begin
data_out <= (others => '0');
case addr is
when "00" =>
data_out <= shift_reg(7 downto 0);
when "01" =>
data_out <= shift_reg(15 downto 8);
when "10" =>
if state = s_idle then
data_out(0) <= '0';
else
data_out(0) <= '1';
end if;
data_out(1) <= deselect;
when others =>
null;
end case;
end process;
 
spi_cs_n <= "11111110" when spi_addr = "000" and spi_cs = '1' else
"11111101" when spi_addr = "001" and spi_cs = '1' else
"11111011" when spi_addr = "010" and spi_cs = '1' else
"11110111" when spi_addr = "011" and spi_cs = '1' else
"11101111" when spi_addr = "100" and spi_cs = '1' else
"11011111" when spi_addr = "101" and spi_cs = '1' else
"10111111" when spi_addr = "110" and spi_cs = '1' else
"01111111" when spi_addr = "111" and spi_cs = '1' else
"11111111";
 
-- SPI transfer state machine
spi_proc : process(clk, reset)
begin
if reset = '1' then
count <= (others => '0');
shift_reg <= (others => '0');
prev_spi_clk <= '0';
spi_clk_out <= '0';
spi_cs <= '0';
state <= s_idle;
irq <= 'Z';
elsif falling_edge(clk) then
prev_spi_clk <= spi_clk_buf;
irq <= 'Z';
case state is
when s_idle =>
if start = '1' then
count <= (others => '0');
shift_reg <= spi_data_buf;
spi_cs <= '1';
state <= s_running;
elsif deselect = '1' then
spi_cs <= '0';
end if;
when s_running =>
if prev_spi_clk = '1' and spi_clk_buf = '0' then
spi_clk_out <= '0';
count <= count + "0001";
shift_reg <= shift_reg(14 downto 0) & spi_miso;
if ((count = "0011" and transfer_length = "00")
or (count = "0111" and transfer_length = "01")
or (count = "1011" and transfer_length = "10")
or (count = "1111" and transfer_length = "11")) then
if deselect = '1' then
spi_cs <= '0';
end if;
if irq_enable = '1' then
irq <= '1';
end if;
state <= s_idle;
end if;
elsif prev_spi_clk = '0' and spi_clk_buf = '1' then
spi_clk_out <= '1';
end if;
when others =>
null;
end case;
end if;
end process;
 
-- Generate SPI clock
spi_clock_gen : process(clk, reset)
begin
if reset = '1' then
spi_clk_count <= (others => '0');
spi_clk_buf <= '0';
elsif falling_edge(clk) then
if state = s_running then
if ((spi_clk_divide = "00")
or (spi_clk_divide = "01" and spi_clk_count = "001")
or (spi_clk_divide = "10" and spi_clk_count = "011")
or (spi_clk_divide = "11" and spi_clk_count = "111")) then
spi_clk_buf <= not spi_clk_buf;
spi_clk_count <= (others => '0');
else
spi_clk_count <= spi_clk_count + "001";
end if;
else
spi_clk_buf <= '0';
end if;
end if;
end process;
 
spi_mosi_mux : process(shift_reg, transfer_length)
begin
case transfer_length is
when "00" =>
spi_mosi <= shift_reg(3);
when "01" =>
spi_mosi <= shift_reg(7);
when "10" =>
spi_mosi <= shift_reg(11);
when "11" =>
spi_mosi <= shift_reg(15);
when others =>
null;
end case;
end process;
spi_clk <= spi_clk_out;
 
end rtl;
/ps2_keyboard.vhd
1,54 → 1,33
---------------------------------------------------------------------------------------
--===========================================================================--
-- --
-- ps2_keyboard.vhd - Synthesizable PS/2 Keyboard Interface --
-- --
--===========================================================================--
--
-- Author: John Clayton
-- Date : April 30, 2001
-- Update: 4/30/01 copied this file from lcd_2.v (pared down).
-- Update: 5/24/01 changed the first module from "ps2_keyboard_receiver"
-- to "ps2_keyboard_interface"
-- Update: 5/29/01 Added input synchronizing flip-flops. Changed state
-- encoding (m1) for good operation after part config.
-- Update: 5/31/01 Added low drive strength and slow transitions to ps2_clk
-- and ps2_data in the constraints file. Added the signal
-- "tx_shifting_done" as distinguished from "rx_shifting_done."
-- Debugged the transmitter portion in the lab.
-- Update: 6/01/01 Added horizontal tab to the ascii output.
-- Update: 6/01/01 Added parameter TRAP_SHIFT_KEYS.
-- Update: 6/05/01 Debugged the "debounce" timer functionality.
-- Used 60usec timer as a "watchdog" timeout during
-- receive from the keyboard. This means that a keyboard
-- can now be "hot plugged" into the interface, without
-- messing up the bit_count, since the bit_count is reset
-- to zero during periods of inactivity anyway. This was
-- difficult to debug. I ended up using the logic analyzer,
-- and had to scratch my head quite a bit.
-- Update: 6/06/01 Removed extra comments before the input synchronizing
-- flip-flops. Used the correct parameter to size the
-- 5usec_timer_count. Changed the name of this file from
-- ps2.v to ps2_keyboard.v
-- Update: 6/06/01 Removed "&& q[7:0]" in output_strobe logic. Removed extra
-- commented out "else" condition in the shift register and
-- bit counter.
-- Update: 6/07/01 Changed default values for 60usec timer parameters so that
-- they correspond to 60usec for a 49.152MHz clock.
-- File name : ps2_keyboard.vhd
--
-- Converted to VHDL: 10 February 2004 - John Kent
-- 11 Sept 04 added ctrl key
-- changed undefined key codes to x"ff"
-- reversed clock polarity
--
-- 18th Oct 04 added ctrl keys to ASCII ROM
-- added CAPS Lock toggle.
--
-- 6th Feb 2007 Added Generic Clock parameter
--
---------------------------------------------------------------------------------------
-- Description:
---------------------------------------------------------------------------------------
-- Purpose : Implements a PS/2 Keyboard Interface
--
-- Dependencies : ieee.std_logic_1164
-- ieee.std_logic_unsigned
-- ieee.std_logic_arith
-- ieee.numeric_std
-- unisim.vcomponents
--
-- Author : Original Verilog version by John Clayton
-- Converted to VHDL by John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- Description :
--
-- This is a state-machine driven serial-to-parallel and parallel-to-serial
-- interface to the ps2 style keyboard interface. The details of the operation
-- of the keyboard interface were obtained from the following website:
--
-- http:--www.beyondlogic.org/keyboard/keybrd.htm
-- http://www.beyondlogic.org/keyboard/keybrd.htm
--
-- Some aspects of the keyboard interface are not implemented (e.g, parity
-- checking for the receive side, and recognition of the various commands
109,48 → 88,112
-- A parameter TRAP_SHIFT_KEYS allows the user to eliminate shift keypresses
-- from producing scan codes (along with their "undefined" ASCII equivalents)
-- at the output of the interface. If TRAP_SHIFT_KEYS is non-zero, the shift
-- key status will only be reported by rx_shift_key_on. No ascii or scan
-- key status will only be reported by rx_shift_on. No ascii or scan
-- codes will be reported for the shift keys. This is useful for those who
-- wish to use the ASCII data stream, and who don't want to have to "filter
-- out" the shift key codes.
--
-- Copyright (C) 2001 - 2010 John Clayton and 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 --
-- --
--===========================================================================--
--
-- Author: John Clayton
-- 2001-04-30 copied this file from lcd_2.v (pared down).
-- 2001-05-24 changed the first module from "ps2_keyboard_receiver"
-- to "ps2_keyboard_interface"
-- 2001-05-29 Added input synchronizing flip-flops. Changed state
-- encoding (m1) for good operation after part config.
-- 2001-05-31 Added low drive strength and slow transitions to ps2_clk
-- and ps2_data in the constraints file. Added the signal
-- "tx_shifting_done" as distinguished from "rx_shifting_done."
-- Debugged the transmitter portion in the lab.
-- 2001-06-01 Added horizontal tab to the ascii output.
-- 2001-06-01 Added parameter TRAP_SHIFT_KEYS.
-- 2001-06-05 Debugged the "debounce" timer functionality.
-- Used 60usec timer as a "watchdog" timeout during
-- receive from the keyboard. This means that a keyboard
-- can now be "hot plugged" into the interface, without
-- messing up the bit_count, since the bit_count is reset
-- to zero during periods of inactivity anyway. This was
-- difficult to debug. I ended up using the logic analyzer,
-- and had to scratch my head quite a bit.
-- 2001-06-06 Removed extra comments before the input synchronizing
-- flip-flops. Used the correct parameter to size the
-- 5usec_timer_count. Changed the name of this file from
-- ps2.v to ps2_keyboard.v
-- 2001-06/06 Removed "&& q[7:0]" in output_strobe logic. Removed extra
-- commented out "else" condition in the shift register and
-- bit counter.
-- 2001-06-07 Changed default values for 60usec timer parameters so that
-- they correspond to 60usec for a 49.152MHz clock.
--
-- Author: John Kent
-- 2001-02-10 Converted to VHDL
-- 2004-09-11 Added ctrl key
-- Changed undefined key codes to x"ff"
-- Reversed clock polarity
-- 2004-10-18 Added ctrl keys to ASCII ROM
-- Added CAPS Lock toggle.
-- 2007-02-06 Added Generic Clock parameter
-- 2010-05-31 Revised header, added GPL
-- 2010-06-17 Change some signal names for consistancy
--
--
--
---------------------------------------------------------------------------------------
 
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
library unisim;
use unisim.vcomponents.all;
 
entity ps2_keyboard_interface is
entity ps2_keyboard is
generic (
Frequency_MHz : integer
CLK_FREQ_MHZ : integer
);
 
port(
clk : in std_logic;
reset : in std_logic;
ps2_clk : inout std_logic;
ps2_data : inout std_logic;
rx_data : out std_logic_vector(7 downto 0);
rx_read : in std_logic;
rx_data_ready : out std_logic;
rx_extended : out std_logic;
rx_released : out std_logic;
rx_shift_key_on : out std_logic;
-- rx_scan_code : out std_logic_vector(7 downto 0);
rx_ascii : out std_logic_vector(7 downto 0);
rx_data_ready : out std_logic; -- rx_read_o
rx_read : in std_logic; -- rx_read_ack_i
rx_shift_on : out std_logic;
tx_data : in std_logic_vector(7 downto 0);
tx_write : in std_logic;
tx_write_ack : out std_logic;
tx_error_no_keyboard_ack : out std_logic
tx_data_empty : out std_logic;
tx_error : out std_logic;
ps2_clk : inout std_logic;
ps2_data : inout std_logic
);
end ps2_keyboard_interface;
end ps2_keyboard;
 
-------------------------------------------------------------------------------
-- Architecture for ps2 keyboard interface
-------------------------------------------------------------------------------
architecture rtl of ps2_keyboard_interface is
architecture rtl of ps2_keyboard is
-----------------------------------------------------------------------------
 
 
185,9 → 228,9
--constant TIMER_5USEC_BITS_PP : integer := 7; -- Number of bits needed for timer
 
-- Values for generic Clock up to 50 MHz
constant TIMER_60USEC_VALUE_PP : integer := Frequency_MHz * 60; -- Number of sys_clks for 60usec.
constant TIMER_60USEC_VALUE_PP : integer := CLK_FREQ_MHZ * 60; -- Number of sys_clks for 60usec.
constant TIMER_60USEC_BITS_PP : integer := 12; -- Number of bits needed for timer
constant TIMER_5USEC_VALUE_PP : integer := Frequency_MHz * 5; -- Number of sys_clks for debounce
constant TIMER_5USEC_VALUE_PP : integer := CLK_FREQ_MHZ * 5; -- Number of sys_clks for debounce
constant TIMER_5USEC_BITS_PP : integer := 8; -- Number of bits needed for timer
 
constant TRAP_SHIFT_KEYS_PP : integer := 1; -- Default: No shift key trap.
209,7 → 252,7
m1_tx_wait_clk_h, m1_tx_force_clk_l,
m1_tx_clk_h, m1_tx_clk_l,
m1_tx_wait_keyboard_ack, m1_tx_done_recovery,
m1_tx_error_no_keyboard_ack, m1_tx_rising_edge_marker,
m1_tx_error, m1_tx_rising_edge_marker,
m1_tx_first_wait_clk_h, m1_tx_first_wait_clk_l, m1_tx_reset_timer,
m1_rx_falling_edge_marker, m1_rx_rising_edge_marker );
 
254,7 → 297,7
signal ps2_data_s : std_logic; -- Synchronous version of this input
signal ps2_clk_hi_z : std_logic; -- Without keyboard, high Z equals 1 due to pullups.
signal ps2_data_hi_z : std_logic; -- Without keyboard, high Z equals 1 due to pullups.
signal tx_write_ack_o : std_logic;
signal tx_data_empty_o : std_logic;
 
--
-- key lookup table
261,13 → 304,13
--
component keymap_rom
Port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector (8 downto 0);
rdata : out std_logic_vector (7 downto 0);
wdata : in std_logic_vector (7 downto 0)
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector (8 downto 0);
data_in : in std_logic_vector (7 downto 0);
data_out : out std_logic_vector (7 downto 0)
);
end component;
 
275,13 → 318,13
 
my_key_map : keymap_rom
Port map (
clk => clk,
rst => reset,
cs => '1',
rw => '1',
addr => shift_key_plus_code,
rdata => ascii,
wdata => "00000000"
clk => clk,
rst => reset,
cs => '1',
rw => '1',
addr => shift_key_plus_code,
data_in => "00000000",
data_out => ascii
);
 
----------------------------------------------------------------------------
291,16 → 334,19
--
ps2_direction : process( ps2_clk_hi_z, ps2_data_hi_z )
begin
 
if( ps2_clk_hi_z = '1' ) then
ps2_clk <= 'Z';
else
ps2_clk <= '0';
end if;
end if;
 
if( ps2_data_hi_z = '1' ) then
ps2_data <= 'Z';
else
ps2_data <= '0';
end if;
end if;
 
end process;
-- Input "synchronizing" logic -- synchronizes the inputs to the state
334,7 → 380,7
-- Output signals default to this value, unless changed in a state condition.
ps2_clk_hi_z <= '1';
ps2_data_hi_z <= '1';
tx_error_no_keyboard_ack <= '0';
tx_error <= '0';
enable_timer_60usec <= '0';
enable_timer_5usec <= '0';
 
435,7 → 481,7
 
when m1_tx_wait_keyboard_ack =>
if (ps2_clk_s = '0') and (ps2_data_s = '1') then
m1_next_state <= m1_tx_error_no_keyboard_ack;
m1_next_state <= m1_tx_error;
elsif (ps2_clk_s = '0') and (ps2_data_s = '0') then
m1_next_state <= m1_tx_done_recovery;
else
449,12 → 495,12
m1_next_state <= m1_tx_done_recovery;
end if;
 
when m1_tx_error_no_keyboard_ack =>
tx_error_no_keyboard_ack <= '1';
when m1_tx_error =>
tx_error <= '1';
if (ps2_clk_s = '1') and (ps2_data_s ='1') then
m1_next_state <= m1_rx_clk_h;
else
m1_next_state <= m1_tx_error_no_keyboard_ack;
m1_next_state <= m1_tx_error;
end if;
 
when others =>
481,7 → 527,7
end if;
end process;
 
assign: process( bit_count, tx_write, tx_write_ack_o, m1_state )
assign: process( bit_count, tx_write, tx_data_empty_o, m1_state )
begin
if (bit_count = TOTAL_BITS) then
rx_shifting_done <= '1';
499,11 → 545,11
-- It also indicates "ack" to the device writing to the transmitter.
if ((tx_write = '1') and (m1_state = m1_rx_clk_h)) or
((tx_write = '1') and (m1_state = m1_rx_clk_l)) then
tx_write_ack_o <= '1';
tx_data_empty_o <= '1';
else
tx_write_ack_o <= '0';
tx_data_empty_o <= '0';
end if;
tx_write_ack <= tx_write_ack_o;
tx_data_empty <= tx_data_empty_o;
end process;
 
-- This is the ODD parity bit for the transmitted word.
513,13 → 559,13
tx_data(3) xor tx_data(2) xor tx_data(1) xor tx_data(0) );
 
-- This is the shift register
q_shift : process(clk, tx_write_ack_o, tx_parity_bit, tx_data,
q_shift : process(clk, tx_data_empty_o, tx_parity_bit, tx_data,
m1_state, q, ps2_data_s, rx_shifting_done )
begin
if clk'event and clk='0' then
if (reset = '1') then
q <= "00000000000";
elsif (tx_write_ack_o = '1') then
elsif (tx_data_empty_o = '1') then
q <= "1" & tx_parity_bit & tx_data & "0";
elsif ( (m1_state = m1_rx_falling_edge_marker) or
(m1_state = m1_tx_rising_edge_marker) ) then
635,7 → 681,7
end process;
 
shift_key_on <= left_shift_key or right_shift_key;
rx_shift_key_on <= shift_key_on;
rx_shift_on <= shift_key_on;
 
--
-- Control keys
683,15 → 729,15
rx_extended <= '0';
rx_released <= '0';
-- rx_scan_code <= "00000000";
rx_ascii <= "00000000";
rx_data <= "00000000";
elsif (rx_output_strobe = '1') then
rx_extended <= hold_extended;
rx_released <= hold_released;
-- rx_scan_code <= q(8 downto 1);
elsif ctrl_key_on = '1' then
rx_ascii <= ascii and x"1f";
rx_data <= ascii and x"1f";
else
rx_ascii <= ascii;
rx_data <= ascii;
end if;
end if;
end process;
/vdu8.vhd
1,523 → 1,631
-- ---------------------------------------------------
-- Video Display terminal
-- ---------------------------------------------------
-- John Kent
-- 3th September 2004
-- Assumes a pixel clock input of 25 MHz
--
-- Display Format is:
-- 80 characters across by 25 characters down.
-- 8 horizontal pixels / character
-- 16 vertical scan lines / character (2 scan lines/row)
--
-- Modified by Bert Cuzeau for compliance and code cleanliness
-- The effort is not over.
-- There are still signal initialized, which is BAD.\
--
-- 7th Februaury 2007 - John Kent
-- Added generics for VGA Timing
--
 
Library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
Library unisim;
use unisim.vcomponents.all;
 
Entity vdu8 is
generic(
VDU_CLOCK_FREQUENCY : integer := 12500000; -- HZ
VGA_CLOCK_FREQUENCY : integer := 25000000; -- HZ
VGA_HOR_CHARS : integer := 80; -- CHARACTERS
VGA_VER_CHARS : integer := 25; -- CHARACTERS
VGA_PIXELS_PER_CHAR : integer := 8; -- PIXELS
VGA_LINES_PER_CHAR : integer := 16; -- LINES
VGA_HOR_BACK_PORCH : integer := 40; -- PIXELS
VGA_HOR_SYNC : integer := 96; -- PIXELS
VGA_HOR_FRONT_PORCH : integer := 24; -- PIXELS
VGA_VER_BACK_PORCH : integer := 13; -- LINES
VGA_VER_SYNC : integer := 1; -- LINES
VGA_VER_FRONT_PORCH : integer := 36 -- LINES
);
port(
-- control register interface
vdu_clk : in std_logic; -- 12.5/25 MHz CPU Clock
vdu_rst : in std_logic;
vdu_cs : in std_logic;
vdu_rw : in std_logic;
vdu_addr : in std_logic_vector(2 downto 0);
vdu_data_in : in std_logic_vector(7 downto 0);
vdu_data_out : out std_logic_vector(7 downto 0);
 
-- vga port connections
vga_clk : in std_logic; -- 25MHz clock
vga_red_o : out std_logic;
vga_green_o : out std_logic;
vga_blue_o : out std_logic;
vga_hsync_o : out std_logic;
vga_vsync_o : out std_logic
);
end vdu8;
 
Architecture RTL of vdu8 is
--
-- Synchronisation constants
--
-- Displayed Characters per row
constant HOR_DISP_CHR : integer := VGA_HOR_CHARS;
-- Last horizontal pixel displayed
constant HOR_DISP_END : integer := (HOR_DISP_CHR * VGA_PIXELS_PER_CHAR) - 1;
-- Start of horizontal synch pulse
constant HOR_SYNC_BEG : integer := HOR_DISP_END + VGA_HOR_BACK_PORCH;
-- End of Horizontal Synch pulse
constant HOR_SYNC_END : integer := HOR_SYNC_BEG + VGA_HOR_SYNC;
-- Last pixel in scan line
constant HOR_SCAN_END : integer := HOR_SYNC_END + VGA_HOR_FRONT_PORCH;
 
-- Displayed Characters per Column
constant VER_DISP_CHR : integer := VGA_VER_CHARS;
-- last row displayed
constant VER_DISP_END : integer := (VER_DISP_CHR * VGA_LINES_PER_CHAR) - 1;
-- start of vertical synch pulse
constant VER_SYNC_BEG : integer := VER_DISP_END + VGA_VER_BACK_PORCH;
-- end of vertical synch pulse
constant VER_SYNC_END : integer := VER_SYNC_BEG + VGA_VER_SYNC;
-- Last scan row in the frame
constant VER_SCAN_END : integer := VER_SYNC_END + VGA_VER_FRONT_PORCH;
 
signal horiz_sync : std_logic := '1';
signal vert_sync : std_logic := '1';
signal cursor_on_v : std_logic;
signal cursor_on_h : std_logic;
signal video_on_v : std_logic := '0';
signal video_on_h : std_logic := '0';
signal h_count : std_logic_vector(9 downto 0) := (others=>'0');
signal v_count : std_logic_vector(8 downto 0) := (others=>'0'); -- 0 to VER_SCAN_END
signal blink_count : std_logic_vector(22 downto 0):= (others=>'1');
--
-- Character generator ROM
--
signal char_addr : std_logic_vector(10 downto 0);
signal char_data_out : std_logic_vector(7 downto 0);
 
--
-- Control Registers
--
signal reg_character : std_logic_vector(7 downto 0);
signal reg_colour : std_logic_vector(7 downto 0);
signal reg_hcursor : std_logic_vector(6 downto 0); -- 80 columns
signal reg_vcursor : std_logic_vector(4 downto 0); -- 25 rows
signal reg_voffset : std_logic_vector(4 downto 0); -- 25 rows
--
-- Video Shift register
--
signal vga_shift : std_logic_vector(7 downto 0);
signal vga_fg_colour : std_logic_vector(2 downto 0);
signal vga_bg_colour : std_logic_vector(2 downto 0);
signal cursor_on : std_logic;
signal cursor_on1 : std_logic;
signal video_on : std_logic := '0';
signal video_on1 : std_logic := '0';
signal video_on2 : std_logic := '0';
--
-- vga character ram access bus
--
signal col_addr : std_logic_vector(6 downto 0) := (others=>'0'); -- 0 to 79
signal row_addr : unsigned(5 downto 0) := (others=>'0'); -- 0 to 49 (25 * 2 -1)
signal col1_addr : std_logic_vector(6 downto 0) := (others=>'0'); -- 0 to 79
signal row1_addr : unsigned(5 downto 0) := (others=>'0'); -- 0 to 49 (25 * 2 - 1)
signal hor_addr : std_logic_vector(6 downto 0) := (others=>'0'); -- 0 to 79
signal ver_addr : std_logic_vector(6 downto 0) := (others=>'0'); -- 0 to 124
signal vga0_cs : std_logic;
signal vga0_rw : std_logic;
signal vga1_cs : std_logic;
signal vga1_rw : std_logic;
signal vga2_cs : std_logic;
signal vga2_rw : std_logic;
signal vga_cs : std_logic;
signal vga_rw : std_logic;
signal vga_addr : std_logic_vector(10 downto 0) := (others=>'0'); -- 2K byte character buffer
signal vga_data_out : std_logic_vector(7 downto 0);
signal attr_data_out : std_logic_vector(7 downto 0);
--
-- Character write handshake signals
--
signal req_write : std_logic; -- request character write
signal ack_write : std_logic;
 
--
-- Block Ram Character gen
--
component char_rom
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector (10 downto 0);
wdata : in std_logic_vector (7 downto 0);
rdata : out std_logic_vector (7 downto 0)
);
end component;
 
component ram_2k
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
-- r_wn : in std_logic;
rw : in std_logic;
addr : in std_logic_vector (10 downto 0);
wdata : in std_logic_vector (7 downto 0);
rdata : out std_logic_vector (7 downto 0)
);
end component;
 
begin
 
--
-- instantiate Character generator ROM
--
vdu_char_rom : char_rom port map(
clk => vga_clk,
rst => vdu_rst,
cs => '1',
rw => '1',
addr => char_addr,
wdata => "00000000",
rdata => char_data_out
);
 
--
-- Character buffer RAM
--
char_buff_ram : ram_2k port map(
clk => vga_clk,
rst => vdu_rst,
cs => vga_cs,
-- r_wn => vga_rw,
rw => vga_rw,
addr => vga_addr,
wdata => reg_character,
rdata => vga_data_out
);
 
--
-- Attribute buffer RAM
--
attr_buff_ram : ram_2k port map(
clk => vga_clk,
rst => vdu_rst,
cs => vga_cs,
-- r_wn => vga_rw,
rw => vga_rw,
addr => vga_addr,
wdata => reg_colour,
rdata => attr_data_out
);
 
--
-- CPU Write interface
--
vga_cpu_write : process(vdu_clk, vdu_rst)
begin
if vdu_rst = '1' then
reg_character <= "00000000";
reg_colour <= "00000111";
reg_hcursor <= "0000000";
reg_vcursor <= "00000";
reg_voffset <= "00000";
req_write <= '0';
 
elsif vdu_clk'event and vdu_clk = '0' then
if (vdu_cs = '1') and (vdu_rw = '0') then
case vdu_addr is
when "000" =>
reg_character <= vdu_data_in;
req_write <= '1';
when "001" =>
reg_colour <= vdu_data_in;
when "010" =>
reg_hcursor <= vdu_data_in(6 downto 0);
when "011" =>
reg_vcursor <= vdu_data_in(4 downto 0);
when others =>
reg_voffset <= vdu_data_in(4 downto 0);
end case;
else
 
if (req_write = '1') and (ack_write = '1') then
req_write <= '0';
else
req_write <= req_write;
end if;
 
end if;
end if;
end process;
--
-- CPU Read interface
--
vga_cpu_read : process(vdu_addr, vdu_cs,
reg_character, reg_colour,
reg_hcursor, reg_vcursor, reg_voffset)
begin
case vdu_addr is
when "000" =>
vdu_data_out <= reg_character;
when "001" =>
vdu_data_out <= reg_colour;
when "010" =>
vdu_data_out <= "0" & reg_hcursor;
when "011" =>
vdu_data_out <= "000" & reg_vcursor;
when others =>
vdu_data_out <= "000" & reg_voffset;
end case;
end process;
 
--
-- Video memory access
--
vga_addr_proc : process(vga_clk, vdu_rst)
begin
 
if vdu_rst = '1' then
vga0_cs <= '0';
vga0_rw <= '1';
row_addr <= "000000";
col_addr <= "0000000";
--
vga1_cs <= '0';
vga1_rw <= '1';
row1_addr <= "000000";
col1_addr <= "0000000";
--
vga2_cs <= '0';
vga2_rw <= '1';
ver_addr <= "0000000";
hor_addr <= "0000000";
--
vga_cs <= '0';
vga_rw <= '1';
vga_addr <= "00000000000";
 
elsif vga_clk'event and vga_clk = '0' then
--
-- on h_count = 0 initiate character write.
-- all other cycles are reads.
--
case h_count(2 downto 0) is
when "000" => -- pipeline character write
vga0_cs <= req_write;
vga0_rw <= '0';
col_addr <= reg_hcursor(6 downto 0);
row_addr <= unsigned("0" & reg_vcursor(4 downto 0)) + unsigned("0" & reg_voffset(4 downto 0));
when others => -- other 6 cycles free
vga0_cs <= '1';
vga0_rw <= '1';
col_addr <= h_count(9 downto 3);
row_addr <= unsigned("0" & v_count(8 downto 4)) + unsigned("0" & reg_voffset(4 downto 0));
end case;
--
-- on vga_clk + 1 round off row address
--
vga1_cs <= vga0_cs;
vga1_rw <= vga0_rw;
if row_addr < VER_DISP_CHR then
row1_addr <= row_addr;
else
row1_addr <= row_addr - VER_DISP_CHR;
end if;
col1_addr <= col_addr;
--
-- on vga_clk + 2 calculate vertical address
--
vga2_cs <= vga1_cs;
vga2_rw <= vga1_rw;
ver_addr <= std_logic_vector(unsigned("00" & row1_addr(4 downto 0)) + unsigned(row1_addr(4 downto 0) & "00"));
hor_addr <= col1_addr;
--
-- on vga_clk + 3 calculate memory address
--
vga_cs <= vga2_cs;
vga_rw <= vga2_rw;
vga_addr <= std_logic_vector(unsigned("0000" & hor_addr) + unsigned(ver_addr & "0000"));
end if;
end process;
--
-- Video shift register
--
vga_shift_proc : process( vga_clk, vdu_rst)
begin
if vdu_rst = '1' then
ack_write <= '0';
video_on2 <= '0';
video_on <= '0';
cursor_on <= '0';
vga_bg_colour <= "000";
vga_fg_colour <= "111";
vga_shift <= "00000000";
vga_red_o <= '0';
vga_green_o <= '0';
vga_blue_o <= '0';
-- Put all video signals through DFFs to elminate any delays that cause a blurry image
 
elsif vga_clk'event and vga_clk = '0' then
-- Character Data valid on 1 count
if h_count(2 downto 0) = "000" then
if (req_write = '1') and (ack_write = '0') then
ack_write <= '1';
elsif (req_write = '0') and (ack_write = '1') then
ack_write <= '0';
else
ack_write <= ack_write;
end if;
video_on2 <= video_on1;
video_on <= video_on2;
cursor_on <= (cursor_on1 or attr_data_out(3)) and blink_count(22);
vga_fg_colour <= attr_data_out(2 downto 0);
vga_bg_colour <= attr_data_out(6 downto 4);
if attr_data_out(7) = '0' then
vga_shift <= char_data_out;
else
case v_count(3 downto 2) is
when "00" =>
vga_shift(7 downto 4) <= vga_data_out(0) & vga_data_out(0) & vga_data_out(0) & vga_data_out(0);
vga_shift(3 downto 0) <= vga_data_out(1) & vga_data_out(1) & vga_data_out(1) & vga_data_out(1);
when "01" =>
vga_shift(7 downto 4) <= vga_data_out(2) & vga_data_out(2) & vga_data_out(2) & vga_data_out(2);
vga_shift(3 downto 0) <= vga_data_out(3) & vga_data_out(3) & vga_data_out(3) & vga_data_out(3);
when "10" =>
vga_shift(7 downto 4) <= vga_data_out(4) & vga_data_out(4) & vga_data_out(4) & vga_data_out(4);
vga_shift(3 downto 0) <= vga_data_out(5) & vga_data_out(5) & vga_data_out(5) & vga_data_out(5);
when others =>
vga_shift(7 downto 4) <= vga_data_out(6) & vga_data_out(6) & vga_data_out(6) & vga_data_out(6);
vga_shift(3 downto 0) <= vga_data_out(7) & vga_data_out(7) & vga_data_out(7) & vga_data_out(7);
end case;
end if;
else
vga_shift <= vga_shift(6 downto 0) & '0';
end if;
 
--
-- Colour mask is
-- 7 6 5 4 3 2 1 0
-- X BG BB BR X FG FB FR
--
if vga_shift(7) = (not cursor_on) then
vga_red_o <= video_on and vga_fg_colour(0);
vga_green_o <= video_on and vga_fg_colour(1);
vga_blue_o <= video_on and vga_fg_colour(2);
else
vga_red_o <= video_on and vga_bg_colour(0);
vga_green_o <= video_on and vga_bg_colour(1);
vga_blue_o <= video_on and vga_bg_colour(2);
end if;
end if;
end process;
 
 
--
-- Sync generator & timing process
-- Generate Horizontal and Vertical Timing Signals for Video Signal
--
vga_sync : process(vga_clk)
begin
if vga_clk'event and vga_clk = '0' then
--
-- H_count counts pixels (640 + extra time for sync signals)
--
-- Horiz_sync -----------------------------__________--------
-- H_count 0 640 659 755 799
--
if unsigned(h_count) = HOR_SCAN_END then
h_count <= (others=>'0');
else
h_count <= std_logic_vector(unsigned(h_count) + 1);
end if;
--
-- Generate Horizontal Sync Signal using H_count
--
if unsigned(h_count) = HOR_SYNC_BEG then
horiz_sync <= '0';
elsif unsigned(h_count) = HOR_SYNC_END then
horiz_sync <= '1';
else
horiz_sync <= horiz_sync;
end if;
--
-- V_count counts rows of pixels
-- 400 lines + extra time for sync signals
-- 25 rows * 16 scan lines
--
-- Vert_sync ---------------------------------_______------------
-- V_count 0 400 413 414 444
--
if (unsigned(v_count) = VER_SCAN_END) and (unsigned(h_count) = HOR_SCAN_END) then
v_count <= "000000000";
elsif unsigned(h_count) = HOR_SYNC_END then
v_count <= std_logic_vector(unsigned(v_count) + 1);
end if;
--
-- Generate Vertical Sync Signal using V_count
--
if unsigned(v_count) = VER_SYNC_BEG then
vert_sync <= '0';
elsif unsigned(v_count) = VER_SYNC_END then
vert_sync <= '1';
else
vert_sync <= vert_sync;
end if;
 
-- Generate Video on Screen Signals for Pixel Data
if unsigned(h_count) = HOR_SCAN_END then
video_on_h <= '1';
elsif unsigned(h_count) = HOR_DISP_END then
video_on_h <= '0';
else
video_on_h <= video_on_h;
end if;
 
if unsigned(v_count) = VER_SCAN_END then
video_on_v <= '1';
elsif unsigned(v_count) = VER_DISP_END then
video_on_v <= '0';
else
video_on_v <= video_on_v;
end if;
 
 
if h_count(9 downto 3) = reg_hcursor(6 downto 0) then
cursor_on_h <= '1';
else
cursor_on_h <= '0';
end if;
 
if (v_count(8 downto 4) = reg_vcursor(4 downto 0)) then
cursor_on_v <= '1';
else
cursor_on_v <= '0';
end if;
 
-- cursor_on is only active when on selected character
blink_count <= std_logic_vector(unsigned(blink_count) + 1);
end if;
 
end process;
 
-- video_on is high only when RGB data is displayed
vga_hsync_o <= horiz_sync;
vga_vsync_o <= vert_sync;
video_on1 <= video_on_H and video_on_V;
cursor_on1 <= cursor_on_h and cursor_on_v;
 
--
-- Here to look up character ROM
-- This will take one clock cycle
-- and should be performed on h_count = "111"
--
char_addr(10 downto 4) <= vga_data_out(6 downto 0);
char_addr(3 downto 0) <= v_count(3 downto 0);
 
end RTL;
--===========================================================================--
-- --
-- vdu8.vhd - Synthesizable Colour Video Display Unit for System09 --
-- --
--===========================================================================--
--
-- File name : vdu8.vhd
--
-- Purpose : Implements a text based Colour Video Display Unit for System09
-- Supports 2KByte Text buffer and 2KByte Attribute memory
-- Displays 80 characters across by 25 character rows
-- Characters are 8 pixels across x 16 lines down.
-- Character attribute bita for foreground and backgrond colour
-- 1 bit for each Blue Green and Red signal
-- Supports 2 x 8 chunky graphics character mode.
-- Uses Generic arguments for setting the video synchronization timing.
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
-- ieee.std_logic_arith
-- ieee.numeric_std
--
-- Uses : ram_2k (ram2k_b16.vhd) 2KByte Character & Attribute buffer
-- char_rom (char_rom2k_b16.vhd) 2KByte Character Generator ROM
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- Description : Display Timing:
-- 800 pixels / line
-- 446 lines / frame
-- None interlaced
-- 25MHz pixel clock implies
-- 31.25 KHz line rate
-- 70.067 Hz frame rate
-- Timing settable by generics.
--
-- Display Size:
-- 80 characters across
-- 25 characters down.
--
-- Character Size:
-- 8 horizontal pixels across
-- 16 vertical scan lines down (2 scan lines/row)
--
-- Registers:
-- Base + 0 ASCII character register
-- Writing to this register writes an 8 bit byte
-- into the text buffer at the specified cursor position
-- Text Mode: ASCII Character (0 to 127)
-- Chunky Graphics Mode: B0 B1 (0 to 255)
-- B2 B3
-- B4 B5
-- B6 B7
-- Base + 1 Attibute bit (0 to 255)
-- Writing to the register writes an 8 bit byte
-- into the attribute buffer at the specified cursor position
-- B7 - 0 => Text Mode / 1 => Chunky Graphics Mode
-- B6 - 1 => Character Background Blue
-- B5 - 1 => Character Background Green
-- B4 - 1 => Character Background Red
-- B3 - 1 => Character Background & Foreground Alternates
-- B2 - 1 => Character Foreground Blue
-- B1 - 1 => Character Foreground Green
-- B0 - 1 => Character Foreground Red
-- Base + 2 Cursor Horizontal Position (0 to 79)
-- Base + 3 Cusror Vertical Position (0 to 24)
-- Base + 4 Vertical Scroll Offset (0 to 24)
-- Scrolls the display up by the specified number of character rows
--
-- Video Timing :
--
-- Horizontal 800 Pixels/ 25MHz Pixel Clock = 32usec Line period = 31.25 KHz Line Frequency
-- /--------------------------\_____________/---------------\______________/
-- 640 Pixels Display 16 Pixel FP 96 Pixel HS 48 Pixel BP
--
-- VGA_CLK_FREQ : integer := 25000000; -- HZ
-- VGA_HOR_FRONT_PORCH : integer := 16; -- PIXELS 0.64us (0.94us)
-- VGA_HOR_SYNC : integer := 96; -- PIXELS 3.84us (3.77us)
-- VGA_HOR_BACK_PORCH : integer := 48; -- PIXELS 1.92us (1.89us)
-- VGA_PIX_PER_CHAR : integer := 8; -- PIXELS 0.32us
-- VGA_HOR_CHARS : integer := 80; -- CHARACTERS 25.6us
--
-- Vertical 446 Lines * 32 usec Line rate = 14.272ms Frame Period = 70.07Hz Frame frequency
-- /---------------------------\____________/---------------\______________/
-- 400 Line Display 10 Line FP 2 Line VS 34 Line BP
--
-- VGA_VER_FRONT_PORCH : integer := 10; -- LINES 0.320ms
-- VGA_VER_SYNC : integer := 2; -- LINES 0.064ms
-- VGA_VER_BACK_PORCH : integer := 34; -- LINES 1.088ms
-- VGA_LIN_PER_CHAR : integer := 16; -- LINES 0.512ms
-- VGA_VER_CHARS : integer := 25; -- CHARACTERS 12.8ms
--
-- 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 Author Date Changes
--
-- 0.1 John Kent 2004-09-03 Initial release
--
-- 0.2 Bert Cuzeau 2007-01-16 Modified by for compliance and code cleanliness
-- The effort is not over.
-- There are still signal initialized, which is BAD.
--
-- 0.3 John Kent 2007-02-07 Added generics for VGA Timing
--
-- 0.4 John Kent 2010-07-03 Added GPL notice.
-- Updated description.
-- Rearranged Video Timing
--
 
Library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
Library unisim;
use unisim.vcomponents.all;
 
Entity vdu8 is
generic(
VGA_CLK_FREQ : integer := 25000000; -- HZ
VGA_HOR_CHARS : integer := 80; -- CHARACTERS 25.6us
VGA_HOR_CHAR_PIXELS : integer := 8; -- PIXELS 0.32us
VGA_HOR_FRONT_PORCH : integer := 16; -- PIXELS 0.64us
VGA_HOR_SYNC : integer := 96; -- PIXELS 3.84us
VGA_HOR_BACK_PORCH : integer := 48; -- PIXELS 1.92us
VGA_VER_CHARS : integer := 25; -- CHARACTERS 12.8ms
VGA_VER_CHAR_LINES : integer := 16; -- LINES 0.512ms
VGA_VER_FRONT_PORCH : integer := 10; -- LINES 0.320ms
VGA_VER_SYNC : integer := 2; -- LINES 0.064ms
VGA_VER_BACK_PORCH : integer := 34 -- LINES 1.088ms
);
port(
-- control register interface
vdu_clk : in std_logic; -- 12.5/25 MHz CPU Clock
vdu_rst : in std_logic;
vdu_cs : in std_logic;
vdu_rw : in std_logic;
vdu_addr : in std_logic_vector(2 downto 0);
vdu_data_in : in std_logic_vector(7 downto 0);
vdu_data_out : out std_logic_vector(7 downto 0);
 
-- vga port connections
vga_clk : in std_logic; -- 25MHz clock
vga_red_o : out std_logic;
vga_green_o : out std_logic;
vga_blue_o : out std_logic;
vga_hsync_o : out std_logic;
vga_vsync_o : out std_logic
);
end vdu8;
 
Architecture RTL of vdu8 is
--
-- Synchronisation constants
--
-- Displayed Characters per row
constant HOR_DISP_CHR : integer := VGA_HOR_CHARS;
-- Last horizontal pixel displayed
constant HOR_DISP_END : integer := (HOR_DISP_CHR * VGA_HOR_CHAR_PIXELS) - 1;
-- Start of horizontal synch pulse
constant HOR_SYNC_BEG : integer := HOR_DISP_END + VGA_HOR_FRONT_PORCH;
-- End of Horizontal Synch pulse
constant HOR_SYNC_END : integer := HOR_SYNC_BEG + VGA_HOR_SYNC;
-- Last pixel in scan line
constant HOR_SCAN_END : integer := HOR_SYNC_END + VGA_HOR_BACK_PORCH;
 
-- Displayed Characters per Column
constant VER_DISP_CHR : integer := VGA_VER_CHARS;
-- last row displayed
constant VER_DISP_END : integer := (VER_DISP_CHR * VGA_VER_CHAR_LINES) - 1;
-- start of vertical synch pulse
constant VER_SYNC_BEG : integer := VER_DISP_END + VGA_VER_FRONT_PORCH;
-- end of vertical synch pulse
constant VER_SYNC_END : integer := VER_SYNC_BEG + VGA_VER_SYNC;
-- Last scan row in the frame
constant VER_SCAN_END : integer := VER_SYNC_END + VGA_VER_BACK_PORCH;
 
signal horiz_sync : std_logic := '1';
signal vert_sync : std_logic := '1';
signal cursor_on_v : std_logic;
signal cursor_on_h : std_logic;
signal video_on_v : std_logic := '0';
signal video_on_h : std_logic := '0';
signal h_count : std_logic_vector(9 downto 0) := (others=>'0');
signal v_count : std_logic_vector(8 downto 0) := (others=>'0'); -- 0 to VER_SCAN_END
signal blink_count : std_logic_vector(22 downto 0):= (others=>'1');
--
-- Character generator ROM
--
signal char_addr : std_logic_vector(10 downto 0);
signal char_data_out : std_logic_vector(7 downto 0);
 
--
-- Control Registers
--
signal reg_character : std_logic_vector(7 downto 0);
signal reg_colour : std_logic_vector(7 downto 0);
signal reg_hcursor : std_logic_vector(6 downto 0); -- 80 columns
signal reg_vcursor : std_logic_vector(4 downto 0); -- 25 rows
signal reg_voffset : std_logic_vector(4 downto 0); -- 25 rows
--
-- Video Shift register
--
signal vga_shift : std_logic_vector(7 downto 0);
signal vga_fg_colour : std_logic_vector(2 downto 0);
signal vga_bg_colour : std_logic_vector(2 downto 0);
signal cursor_on : std_logic;
signal cursor_on1 : std_logic;
signal video_on : std_logic := '0';
signal video_on1 : std_logic := '0';
signal video_on2 : std_logic := '0';
--
-- vga character ram access bus
--
signal col_addr : std_logic_vector(6 downto 0) := (others=>'0'); -- 0 to 79
signal row_addr : unsigned(5 downto 0) := (others=>'0'); -- 0 to 49 (25 * 2 -1)
signal col1_addr : std_logic_vector(6 downto 0) := (others=>'0'); -- 0 to 79
signal row1_addr : unsigned(5 downto 0) := (others=>'0'); -- 0 to 49 (25 * 2 - 1)
signal hor_addr : std_logic_vector(6 downto 0) := (others=>'0'); -- 0 to 79
signal ver_addr : std_logic_vector(6 downto 0) := (others=>'0'); -- 0 to 124
signal vga0_cs : std_logic;
signal vga0_rw : std_logic;
signal vga1_cs : std_logic;
signal vga1_rw : std_logic;
signal vga2_cs : std_logic;
signal vga2_rw : std_logic;
signal vga_cs : std_logic;
signal vga_rw : std_logic;
signal vga_addr : std_logic_vector(10 downto 0) := (others=>'0'); -- 2K byte character buffer
signal vga_data_out : std_logic_vector(7 downto 0);
signal attr_data_out : std_logic_vector(7 downto 0);
--
-- Character write handshake signals
--
signal req_write : std_logic; -- request character write
signal ack_write : std_logic;
 
--
-- Block Ram Character gen
--
component char_rom
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector (10 downto 0);
data_in : in std_logic_vector (7 downto 0);
data_out : out std_logic_vector (7 downto 0)
);
end component;
 
component ram_2k
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector (10 downto 0);
data_in : in std_logic_vector (7 downto 0);
data_out : out std_logic_vector (7 downto 0)
);
end component;
 
begin
 
--
-- instantiate Character generator ROM
--
vdu_char_rom : char_rom port map(
clk => vga_clk,
rst => vdu_rst,
cs => '1',
rw => '1',
addr => char_addr,
data_in => "00000000",
data_out => char_data_out
);
 
--
-- Character buffer RAM
--
char_buff_ram : ram_2k port map(
clk => vga_clk,
rst => vdu_rst,
cs => vga_cs,
rw => vga_rw,
addr => vga_addr,
data_in => reg_character,
data_out => vga_data_out
);
 
--
-- Attribute buffer RAM
--
attr_buff_ram : ram_2k port map(
clk => vga_clk,
rst => vdu_rst,
cs => vga_cs,
rw => vga_rw,
addr => vga_addr,
data_in => reg_colour,
data_out => attr_data_out
);
 
--
-- CPU Write interface
--
vga_cpu_write : process(vdu_clk, vdu_rst)
begin
if vdu_rst = '1' then
reg_character <= "00000000";
reg_colour <= "00000111";
reg_hcursor <= "0000000";
reg_vcursor <= "00000";
reg_voffset <= "00000";
req_write <= '0';
 
elsif vdu_clk'event and vdu_clk = '0' then
if (vdu_cs = '1') and (vdu_rw = '0') then
case vdu_addr is
when "000" =>
reg_character <= vdu_data_in;
req_write <= '1';
when "001" =>
reg_colour <= vdu_data_in;
when "010" =>
reg_hcursor <= vdu_data_in(6 downto 0);
when "011" =>
reg_vcursor <= vdu_data_in(4 downto 0);
when others =>
reg_voffset <= vdu_data_in(4 downto 0);
end case;
else
 
if (req_write = '1') and (ack_write = '1') then
req_write <= '0';
else
req_write <= req_write;
end if;
 
end if;
end if;
end process;
--
-- CPU Read interface
--
vga_cpu_read : process(vdu_addr, vdu_cs,
reg_character, reg_colour,
reg_hcursor, reg_vcursor, reg_voffset)
begin
case vdu_addr is
when "000" =>
vdu_data_out <= reg_character;
when "001" =>
vdu_data_out <= reg_colour;
when "010" =>
vdu_data_out <= "0" & reg_hcursor;
when "011" =>
vdu_data_out <= "000" & reg_vcursor;
when others =>
vdu_data_out <= "000" & reg_voffset;
end case;
end process;
 
--
-- Video memory access
--
vga_addr_proc : process(vga_clk, vdu_rst)
begin
 
if vdu_rst = '1' then
vga0_cs <= '0';
vga0_rw <= '1';
row_addr <= "000000";
col_addr <= "0000000";
--
vga1_cs <= '0';
vga1_rw <= '1';
row1_addr <= "000000";
col1_addr <= "0000000";
--
vga2_cs <= '0';
vga2_rw <= '1';
ver_addr <= "0000000";
hor_addr <= "0000000";
--
vga_cs <= '0';
vga_rw <= '1';
vga_addr <= "00000000000";
 
elsif vga_clk'event and vga_clk = '0' then
--
-- on h_count = 0 initiate character write.
-- all other cycles are reads.
--
case h_count(2 downto 0) is
when "000" => -- pipeline character write
vga0_cs <= req_write;
vga0_rw <= '0';
col_addr <= reg_hcursor(6 downto 0);
row_addr <= unsigned("0" & reg_vcursor(4 downto 0)) + unsigned("0" & reg_voffset(4 downto 0));
when others => -- other 6 cycles free
vga0_cs <= '1';
vga0_rw <= '1';
col_addr <= h_count(9 downto 3);
row_addr <= unsigned("0" & v_count(8 downto 4)) + unsigned("0" & reg_voffset(4 downto 0));
end case;
--
-- on vga_clk + 1 round off row address
--
vga1_cs <= vga0_cs;
vga1_rw <= vga0_rw;
if row_addr < VER_DISP_CHR then
row1_addr <= row_addr;
else
row1_addr <= row_addr - VER_DISP_CHR;
end if;
col1_addr <= col_addr;
--
-- on vga_clk + 2 calculate vertical address
--
vga2_cs <= vga1_cs;
vga2_rw <= vga1_rw;
ver_addr <= std_logic_vector(unsigned("00" & row1_addr(4 downto 0)) + unsigned(row1_addr(4 downto 0) & "00"));
hor_addr <= col1_addr;
--
-- on vga_clk + 3 calculate memory address
--
vga_cs <= vga2_cs;
vga_rw <= vga2_rw;
vga_addr <= std_logic_vector(unsigned("0000" & hor_addr) + unsigned(ver_addr & "0000"));
end if;
end process;
--
-- Video shift register
--
vga_shift_proc : process( vga_clk, vdu_rst)
begin
if vdu_rst = '1' then
ack_write <= '0';
video_on2 <= '0';
video_on <= '0';
cursor_on <= '0';
vga_bg_colour <= "000";
vga_fg_colour <= "111";
vga_shift <= "00000000";
vga_red_o <= '0';
vga_green_o <= '0';
vga_blue_o <= '0';
-- Put all video signals through DFFs to elminate any delays that cause a blurry image
 
elsif vga_clk'event and vga_clk = '0' then
-- Character Data valid on 1 count
if h_count(2 downto 0) = "000" then
if (req_write = '1') and (ack_write = '0') then
ack_write <= '1';
elsif (req_write = '0') and (ack_write = '1') then
ack_write <= '0';
else
ack_write <= ack_write;
end if;
video_on2 <= video_on1;
video_on <= video_on2;
cursor_on <= (cursor_on1 or attr_data_out(3)) and blink_count(22);
vga_fg_colour <= attr_data_out(2 downto 0);
vga_bg_colour <= attr_data_out(6 downto 4);
if attr_data_out(7) = '0' then
vga_shift <= char_data_out;
else
case v_count(3 downto 2) is
when "00" =>
vga_shift(7 downto 4) <= vga_data_out(0) & vga_data_out(0) & vga_data_out(0) & vga_data_out(0);
vga_shift(3 downto 0) <= vga_data_out(1) & vga_data_out(1) & vga_data_out(1) & vga_data_out(1);
when "01" =>
vga_shift(7 downto 4) <= vga_data_out(2) & vga_data_out(2) & vga_data_out(2) & vga_data_out(2);
vga_shift(3 downto 0) <= vga_data_out(3) & vga_data_out(3) & vga_data_out(3) & vga_data_out(3);
when "10" =>
vga_shift(7 downto 4) <= vga_data_out(4) & vga_data_out(4) & vga_data_out(4) & vga_data_out(4);
vga_shift(3 downto 0) <= vga_data_out(5) & vga_data_out(5) & vga_data_out(5) & vga_data_out(5);
when others =>
vga_shift(7 downto 4) <= vga_data_out(6) & vga_data_out(6) & vga_data_out(6) & vga_data_out(6);
vga_shift(3 downto 0) <= vga_data_out(7) & vga_data_out(7) & vga_data_out(7) & vga_data_out(7);
end case;
end if;
else
vga_shift <= vga_shift(6 downto 0) & '0';
end if;
 
--
-- Colour mask is
-- 7 6 5 4 3 2 1 0
-- X BG BB BR X FG FB FR
--
if vga_shift(7) = (not cursor_on) then
vga_red_o <= video_on and vga_fg_colour(0);
vga_green_o <= video_on and vga_fg_colour(1);
vga_blue_o <= video_on and vga_fg_colour(2);
else
vga_red_o <= video_on and vga_bg_colour(0);
vga_green_o <= video_on and vga_bg_colour(1);
vga_blue_o <= video_on and vga_bg_colour(2);
end if;
end if;
end process;
 
 
--
-- Sync generator & timing process
-- Generate Horizontal and Vertical Timing Signals for Video Signal
--
vga_sync : process(vga_clk)
begin
if vga_clk'event and vga_clk = '0' then
--
-- H_count counts pixels (640 + extra time for sync signals)
--
-- Horiz_sync -----------------------------__________--------
-- H_count 0 640 659 755 799
--
if unsigned(h_count) = HOR_SCAN_END then
h_count <= (others=>'0');
else
h_count <= std_logic_vector(unsigned(h_count) + 1);
end if;
--
-- Generate Horizontal Sync Signal using H_count
--
if unsigned(h_count) = HOR_SYNC_BEG then
horiz_sync <= '0';
elsif unsigned(h_count) = HOR_SYNC_END then
horiz_sync <= '1';
else
horiz_sync <= horiz_sync;
end if;
--
-- V_count counts rows of pixels
-- 400 lines + extra time for sync signals
-- 25 rows * 16 scan lines
--
-- Vert_sync ---------------------------------_______------------
-- V_count 0 400 413 414 444
--
if (unsigned(v_count) = VER_SCAN_END) and (unsigned(h_count) = HOR_SCAN_END) then
v_count <= "000000000";
elsif unsigned(h_count) = HOR_SYNC_END then
v_count <= std_logic_vector(unsigned(v_count) + 1);
end if;
--
-- Generate Vertical Sync Signal using V_count
--
if unsigned(v_count) = VER_SYNC_BEG then
vert_sync <= '0';
elsif unsigned(v_count) = VER_SYNC_END then
vert_sync <= '1';
else
vert_sync <= vert_sync;
end if;
 
-- Generate Video on Screen Signals for Pixel Data
if unsigned(h_count) = HOR_SCAN_END then
video_on_h <= '1';
elsif unsigned(h_count) = HOR_DISP_END then
video_on_h <= '0';
else
video_on_h <= video_on_h;
end if;
 
if unsigned(v_count) = VER_SCAN_END then
video_on_v <= '1';
elsif unsigned(v_count) = VER_DISP_END then
video_on_v <= '0';
else
video_on_v <= video_on_v;
end if;
 
 
if h_count(9 downto 3) = reg_hcursor(6 downto 0) then
cursor_on_h <= '1';
else
cursor_on_h <= '0';
end if;
 
if (v_count(8 downto 4) = reg_vcursor(4 downto 0)) then
cursor_on_v <= '1';
else
cursor_on_v <= '0';
end if;
 
-- cursor_on is only active when on selected character
blink_count <= std_logic_vector(unsigned(blink_count) + 1);
end if;
 
end process;
 
-- video_on is high only when RGB data is displayed
vga_hsync_o <= horiz_sync;
vga_vsync_o <= vert_sync;
video_on1 <= video_on_H and video_on_V;
cursor_on1 <= cursor_on_h and cursor_on_v;
 
--
-- Here to look up character ROM
-- This will take one clock cycle
-- and should be performed on h_count = "111"
--
char_addr(10 downto 4) <= vga_data_out(6 downto 0);
char_addr(3 downto 0) <= v_count(3 downto 0);
 
end RTL;
/BaudClock.vhd
1,12 → 1,57
-----------------------------------------------------------------
--===========================================================================--
-- --
-- BaudClock.vhd - Synthesizable Baud Rate Clock Divider --
-- --
--===========================================================================--
--
-- ACIA Clock Divider for System09
-- File name : BaudClock.vhd
--
-----------------------------------------------------------------
-- Purpose : Implements a baud rate clock divider for a 6850 compatible
-- Asynchronous Communications Interface Adapter
--
-- Dependencies : ieee.std_logic_1164
-- ieee.std_logic_arith
-- ieee.std_logic_unsigned
-- ieee.numeric_std
-- unisim.vcomponents
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- BaudClock.vhd is baud rate clock divider for a 6850 compatible ACIA core.
--
-- 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 --
-- --
--===========================================================================--
--
-- Revision Name Date Description
-- 0.1 John E. Kent unknown Initial version
-- 1.0 John E. Kent 30th May 2010 Added GPL Header
--
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
library unisim;
use unisim.vcomponents.all;
/pia6821.vhd
1,530 → 1,523
--===========================================================================--
--
-- S Y N T H E Z I A B L E I/O Port C O R E
--
-- www.OpenCores.Org - May 2004
-- This core adheres to the GNU public license
--
-- File name : pia6821.vhd
--
-- Purpose : Implements 2 x 8 bit parallel I/O ports
-- with programmable data direction registers
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
--
-- Author : John E. Kent
--
--===========================================================================----
--
-- Revision History:
--
-- Date: Revision Author
-- 1 May 2004 0.0 John Kent
-- Initial version developed from ioport.vhd
--
--===========================================================================----
--
-- Memory Map
--
-- IO + $00 - Port A Data & Direction register
-- IO + $01 - Port A Control register
-- IO + $02 - Port B Data & Direction Direction Register
-- IO + $03 - Port B Control Register
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity pia6821 is
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector(1 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
irqa : out std_logic;
irqb : out std_logic;
pa : inout std_logic_vector(7 downto 0);
ca1 : in std_logic;
ca2 : inout std_logic;
pb : inout std_logic_vector(7 downto 0);
cb1 : in std_logic;
cb2 : inout std_logic
);
end;
 
architecture pia_arch of pia6821 is
 
signal porta_ddr : std_logic_vector(7 downto 0);
signal porta_data : std_logic_vector(7 downto 0);
signal porta_ctrl : std_logic_vector(5 downto 0);
signal porta_read : std_logic;
 
signal portb_ddr : std_logic_vector(7 downto 0);
signal portb_data : std_logic_vector(7 downto 0);
signal portb_ctrl : std_logic_vector(5 downto 0);
signal portb_read : std_logic;
signal portb_write : std_logic;
 
signal ca1_del : std_logic;
signal ca1_rise : std_logic;
signal ca1_fall : std_logic;
signal ca1_edge : std_logic;
signal irqa1 : std_logic;
 
signal ca2_del : std_logic;
signal ca2_rise : std_logic;
signal ca2_fall : std_logic;
signal ca2_edge : std_logic;
signal irqa2 : std_logic;
signal ca2_out : std_logic;
 
signal cb1_del : std_logic;
signal cb1_rise : std_logic;
signal cb1_fall : std_logic;
signal cb1_edge : std_logic;
signal irqb1 : std_logic;
 
signal cb2_del : std_logic;
signal cb2_rise : std_logic;
signal cb2_fall : std_logic;
signal cb2_edge : std_logic;
signal irqb2 : std_logic;
signal cb2_out : std_logic;
 
begin
 
--------------------------------
--
-- read I/O port
--
--------------------------------
 
pia_read : process( addr, cs,
irqa1, irqa2, irqb1, irqb2,
porta_ddr, portb_ddr,
porta_data, portb_data,
porta_ctrl, portb_ctrl,
pa, pb )
variable count : integer;
begin
case addr is
when "00" =>
for count in 0 to 7 loop
if porta_ctrl(2) = '0' then
data_out(count) <= porta_ddr(count);
porta_read <= '0';
else
if porta_ddr(count) = '1' then
data_out(count) <= porta_data(count);
else
data_out(count) <= pa(count);
end if;
porta_read <= cs;
end if;
end loop;
portb_read <= '0';
 
when "01" =>
data_out <= irqa1 & irqa2 & porta_ctrl;
porta_read <= '0';
portb_read <= '0';
 
when "10" =>
for count in 0 to 7 loop
if portb_ctrl(2) = '0' then
data_out(count) <= portb_ddr(count);
portb_read <= '0';
else
if portb_ddr(count) = '1' then
data_out(count) <= portb_data(count);
else
data_out(count) <= pb(count);
end if;
portb_read <= cs;
end if;
end loop;
porta_read <= '0';
 
when "11" =>
data_out <= irqb1 & irqb2 & portb_ctrl;
porta_read <= '0';
portb_read <= '0';
 
when others =>
data_out <= "00000000";
porta_read <= '0';
portb_read <= '0';
 
end case;
end process;
 
---------------------------------
--
-- Write I/O ports
--
---------------------------------
 
pia_write : process( clk, rst, addr, cs, rw, data_in,
porta_ctrl, portb_ctrl,
porta_data, portb_data,
porta_ctrl, portb_ctrl,
porta_ddr, portb_ddr )
begin
if rst = '1' then
porta_ddr <= "00000000";
porta_data <= "00000000";
porta_ctrl <= "000000";
portb_ddr <= "00000000";
portb_data <= "00000000";
portb_ctrl <= "000000";
portb_write <= '0';
elsif clk'event and clk = '1' then
if cs = '1' and rw = '0' then
case addr is
when "00" =>
if porta_ctrl(2) = '0' then
porta_ddr <= data_in;
porta_data <= porta_data;
else
porta_ddr <= porta_ddr;
porta_data <= data_in;
end if;
porta_ctrl <= porta_ctrl;
portb_ddr <= portb_ddr;
portb_data <= portb_data;
portb_ctrl <= portb_ctrl;
portb_write <= '0';
when "01" =>
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= data_in(5 downto 0);
portb_ddr <= portb_ddr;
portb_data <= portb_data;
portb_ctrl <= portb_ctrl;
portb_write <= '0';
when "10" =>
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= porta_ctrl;
if portb_ctrl(2) = '0' then
portb_ddr <= data_in;
portb_data <= portb_data;
portb_write <= '0';
else
portb_ddr <= portb_ddr;
portb_data <= data_in;
portb_write <= '1';
end if;
portb_ctrl <= portb_ctrl;
when "11" =>
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= porta_ctrl;
portb_ddr <= portb_ddr;
portb_data <= portb_data;
portb_ctrl <= data_in(5 downto 0);
portb_write <= '0';
when others =>
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= porta_ctrl;
portb_ddr <= portb_ddr;
portb_data <= portb_data;
portb_ctrl <= portb_ctrl;
portb_write <= '0';
end case;
else
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= porta_ctrl;
portb_data <= portb_data;
portb_ddr <= portb_ddr;
portb_ctrl <= portb_ctrl;
portb_write <= '0';
end if;
end if;
end process;
 
---------------------------------
--
-- direction control port a
--
---------------------------------
porta_direction : process ( porta_data, porta_ddr )
variable count : integer;
begin
for count in 0 to 7 loop
if porta_ddr(count) = '1' then
pa(count) <= porta_data(count);
else
pa(count) <= 'Z';
end if;
end loop;
end process;
 
---------------------------------
--
-- CA1 Edge detect
--
---------------------------------
ca1_input : process( clk, rst, ca1, ca1_del,
ca1_rise, ca1_fall, ca1_edge,
irqa1, porta_ctrl, porta_read )
begin
if rst = '1' then
ca1_del <= '0';
ca1_rise <= '0';
ca1_fall <= '0';
ca1_edge <= '0';
irqa1 <= '0';
elsif clk'event and clk = '0' then
ca1_del <= ca1;
ca1_rise <= (not ca1_del) and ca1;
ca1_fall <= ca1_del and (not ca1);
if ca1_edge = '1' then
irqa1 <= '1';
elsif porta_read = '1' then
irqa1 <= '0';
else
irqa1 <= irqa1;
end if;
end if;
 
if porta_ctrl(1) = '0' then
ca1_edge <= ca1_fall;
else
ca1_edge <= ca1_rise;
end if;
end process;
 
---------------------------------
--
-- CA2 Edge detect
--
---------------------------------
ca2_input : process( clk, rst, ca2, ca2_del,
ca2_rise, ca2_fall, ca2_edge,
irqa2, porta_ctrl, porta_read )
begin
if rst = '1' then
ca2_del <= '0';
ca2_rise <= '0';
ca2_fall <= '0';
ca2_edge <= '0';
irqa2 <= '0';
elsif clk'event and clk = '0' then
ca2_del <= ca2;
ca2_rise <= (not ca2_del) and ca2;
ca2_fall <= ca2_del and (not ca2);
if porta_ctrl(5) = '0' and ca2_edge = '1' then
irqa2 <= '1';
elsif porta_read = '1' then
irqa2 <= '0';
else
irqa2 <= irqa2;
end if;
end if;
 
if porta_ctrl(4) = '0' then
ca2_edge <= ca2_fall;
else
ca2_edge <= ca2_rise;
end if;
end process;
 
---------------------------------
--
-- CA2 output control
--
---------------------------------
ca2_output : process( clk, rst, porta_ctrl, porta_read, ca1_edge, ca2_out )
begin
if rst='1' then
ca2_out <= '0';
elsif clk'event and clk='0' then
case porta_ctrl(5 downto 3) is
when "100" => -- read PA clears, CA1 edge sets
if porta_read = '1' then
ca2_out <= '0';
elsif ca1_edge = '1' then
ca2_out <= '1';
else
ca2_out <= ca2_out;
end if;
when "101" => -- read PA clears, E sets
ca2_out <= not porta_read;
when "110" => -- set low
ca2_out <= '0';
when "111" => -- set high
ca2_out <= '1';
when others => -- no change
ca2_out <= ca2_out;
end case;
end if;
end process;
 
---------------------------------
--
-- CA2 direction control
--
---------------------------------
ca2_direction : process( porta_ctrl, ca2, ca2_out )
begin
if porta_ctrl(5) = '0' then
ca2 <= 'Z';
else
ca2 <= ca2_out;
end if;
end process;
 
---------------------------------
--
-- direction control port b
--
---------------------------------
portb_direction : process ( portb_data, portb_ddr )
variable count : integer;
begin
for count in 0 to 7 loop
if portb_ddr(count) = '1' then
pb(count) <= portb_data(count);
else
pb(count) <= 'Z';
end if;
end loop;
end process;
 
---------------------------------
--
-- CB1 Edge detect
--
---------------------------------
cb1_input : process( clk, rst, cb1, cb1_del,
cb1_rise, cb1_fall, cb1_edge,
irqb1, portb_ctrl, portb_read )
begin
if rst = '1' then
cb1_del <= '0';
cb1_rise <= '0';
cb1_fall <= '0';
cb1_edge <= '0';
irqb1 <= '0';
elsif clk'event and clk = '0' then
cb1_del <= cb1;
cb1_rise <= (not cb1_del) and cb1;
cb1_fall <= cb1_del and (not cb1);
if cb1_edge = '1' then
irqb1 <= '1';
elsif portb_read = '1' then
irqb1 <= '0';
else
irqb1 <= irqb1;
end if;
end if;
if portb_ctrl(1) = '0' then
cb1_edge <= cb1_fall;
else
cb1_edge <= cb1_rise;
end if;
end process;
 
---------------------------------
--
-- CB2 Edge detect
--
---------------------------------
cb2_input : process( clk, rst, cb2, cb2_del,
cb2_rise, cb2_fall, cb2_edge,
irqb2, portb_ctrl, portb_read )
begin
if rst = '1' then
cb2_del <= '0';
cb2_rise <= '0';
cb2_fall <= '0';
cb2_edge <= '0';
irqb2 <= '0';
elsif clk'event and clk = '0' then
cb2_del <= cb2;
cb2_rise <= (not cb2_del) and cb2;
cb2_fall <= cb2_del and (not cb2);
if portb_ctrl(5) = '0' and cb2_edge = '1' then
irqb2 <= '1';
elsif portb_read = '1' then
irqb2 <= '0';
else
irqb2 <= irqb2;
end if;
end if;
if portb_ctrl(4) = '0' then
cb2_edge <= cb2_fall;
else
cb2_edge <= cb2_rise;
end if;
 
end process;
 
---------------------------------
--
-- CB2 output control
--
---------------------------------
cb2_output : process( clk, rst, portb_ctrl, portb_write, cb1_edge, cb2_out )
begin
if rst='1' then
cb2_out <= '0';
elsif clk'event and clk='0' then
case portb_ctrl(5 downto 3) is
when "100" => -- write PB clears, CA1 edge sets
if portb_write = '1' then
cb2_out <= '0';
elsif cb1_edge = '1' then
cb2_out <= '1';
else
cb2_out <= cb2_out;
end if;
when "101" => -- write PB clears, E sets
cb2_out <= not portb_write;
when "110" => -- set low
cb2_out <= '0';
when "111" => -- set high
cb2_out <= '1';
when others => -- no change
cb2_out <= cb2_out;
end case;
end if;
end process;
 
---------------------------------
--
-- CB2 direction control
--
---------------------------------
cb2_direction : process( portb_ctrl, cb2, cb2_out )
begin
if portb_ctrl(5) = '0' then
cb2 <= 'Z';
else
cb2 <= cb2_out;
end if;
end process;
 
---------------------------------
--
-- IRQ control
--
---------------------------------
pia_irq : process( irqa1, irqa2, irqb1, irqb2, porta_ctrl, portb_ctrl )
begin
irqa <= (irqa1 and porta_ctrl(0)) or (irqa2 and porta_ctrl(3));
irqb <= (irqb1 and portb_ctrl(0)) or (irqb2 and portb_ctrl(3));
end process;
 
end pia_arch;
--===========================================================================--
-- --
-- Synthesizable 6821 Compatible Parallel Interface Adapter --
-- --
--===========================================================================--
--
-- File name : pia6821.vhd
--
-- Entity name : pia6821
--
-- Purpose : Implements a 6821 like PIA with
-- 2 x 8 bit parallel I/O ports with
-- programmable data direction registers and
-- 2 x 2 bit control signals.
--
-- 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
--
-- Description : Register Memory Map
--
-- Base + $00 - Port A Data & Direction register
-- Base + $01 - Port A Control register
-- Base + $02 - Port B Data & Direction Direction Register
-- Base + $03 - Port B Control Register
--
-- Copyright (C) 2004 - 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 Author Date Description
-- 0.0 John Kent 2004-05-01 Initial version developed from ioport.vhd
-- 0.1 John Kent 2010-05-30 Updated header & GPL information
-- 0.2 John Kent 2010-08-09 Made reset synchronous for wishbone compliance
--
--===========================================================================--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
library unisim;
use unisim.vcomponents.all;
 
entity pia6821 is
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector(1 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
irqa : out std_logic;
irqb : out std_logic;
pa : inout std_logic_vector(7 downto 0);
ca1 : in std_logic;
ca2 : inout std_logic;
pb : inout std_logic_vector(7 downto 0);
cb1 : in std_logic;
cb2 : inout std_logic
);
end;
 
architecture pia_arch of pia6821 is
 
signal porta_ddr : std_logic_vector(7 downto 0);
signal porta_data : std_logic_vector(7 downto 0);
signal porta_ctrl : std_logic_vector(5 downto 0);
signal porta_read : std_logic;
 
signal portb_ddr : std_logic_vector(7 downto 0);
signal portb_data : std_logic_vector(7 downto 0);
signal portb_ctrl : std_logic_vector(5 downto 0);
signal portb_read : std_logic;
signal portb_write : std_logic;
 
signal ca1_del : std_logic;
signal ca1_rise : std_logic;
signal ca1_fall : std_logic;
signal ca1_edge : std_logic;
signal irqa1 : std_logic;
 
signal ca2_del : std_logic;
signal ca2_rise : std_logic;
signal ca2_fall : std_logic;
signal ca2_edge : std_logic;
signal irqa2 : std_logic;
signal ca2_out : std_logic;
 
signal cb1_del : std_logic;
signal cb1_rise : std_logic;
signal cb1_fall : std_logic;
signal cb1_edge : std_logic;
signal irqb1 : std_logic;
 
signal cb2_del : std_logic;
signal cb2_rise : std_logic;
signal cb2_fall : std_logic;
signal cb2_edge : std_logic;
signal irqb2 : std_logic;
signal cb2_out : std_logic;
 
begin
 
--------------------------------
--
-- read I/O port
--
--------------------------------
 
pia_read : process( addr, cs,
irqa1, irqa2, irqb1, irqb2,
porta_ddr, portb_ddr,
porta_data, portb_data,
porta_ctrl, portb_ctrl,
pa, pb )
variable count : integer;
begin
case addr is
when "00" =>
for count in 0 to 7 loop
if porta_ctrl(2) = '0' then
data_out(count) <= porta_ddr(count);
porta_read <= '0';
else
if porta_ddr(count) = '1' then
data_out(count) <= porta_data(count);
else
data_out(count) <= pa(count);
end if;
porta_read <= cs;
end if;
end loop;
portb_read <= '0';
 
when "01" =>
data_out <= irqa1 & irqa2 & porta_ctrl;
porta_read <= '0';
portb_read <= '0';
 
when "10" =>
for count in 0 to 7 loop
if portb_ctrl(2) = '0' then
data_out(count) <= portb_ddr(count);
portb_read <= '0';
else
if portb_ddr(count) = '1' then
data_out(count) <= portb_data(count);
else
data_out(count) <= pb(count);
end if;
portb_read <= cs;
end if;
end loop;
porta_read <= '0';
 
when "11" =>
data_out <= irqb1 & irqb2 & portb_ctrl;
porta_read <= '0';
portb_read <= '0';
 
when others =>
data_out <= "00000000";
porta_read <= '0';
portb_read <= '0';
 
end case;
 
end process;
 
---------------------------------
--
-- Write I/O ports
--
---------------------------------
 
pia_write : process( clk, rst, addr, cs, rw, data_in,
porta_ctrl, portb_ctrl,
porta_data, portb_data,
porta_ctrl, portb_ctrl,
porta_ddr, portb_ddr )
begin
if clk'event and clk = '1' then
portb_write <= '0';
if rst = '1' then
porta_ddr <= (others=>'0');
porta_data <= (others=>'0');
porta_ctrl <= (others=>'0');
portb_ddr <= (others=>'0');
portb_data <= (others=>'0');
portb_ctrl <= (others=>'0');
elsif cs = '1' and rw = '0' then
case addr is
when "00" =>
if porta_ctrl(2) = '0' then
porta_ddr <= data_in;
else
porta_data <= data_in;
end if;
when "01" =>
porta_ctrl <= data_in(5 downto 0);
when "10" =>
if portb_ctrl(2) = '0' then
portb_ddr <= data_in;
else
portb_data <= data_in;
portb_write <= '1';
end if;
when "11" =>
portb_ctrl <= data_in(5 downto 0);
when others =>
null;
end case;
end if;
end if;
end process;
 
---------------------------------
--
-- direction control port a
--
---------------------------------
porta_direction : process ( porta_data, porta_ddr )
variable count : integer;
begin
for count in 0 to 7 loop
if porta_ddr(count) = '1' then
pa(count) <= porta_data(count);
else
pa(count) <= 'Z';
end if;
end loop;
end process;
 
---------------------------------
--
-- CA1 Edge detect
--
---------------------------------
ca1_input : process( clk, rst, ca1, ca1_del,
ca1_rise, ca1_fall, ca1_edge,
irqa1, porta_ctrl, porta_read )
begin
if clk'event and clk = '0' then
if rst = '1' then
ca1_del <= '0';
ca1_rise <= '0';
ca1_fall <= '0';
irqa1 <= '0';
else
ca1_del <= ca1;
ca1_rise <= (not ca1_del) and ca1;
ca1_fall <= ca1_del and (not ca1);
if ca1_edge = '1' then
irqa1 <= '1';
elsif porta_read = '1' then
irqa1 <= '0';
end if;
end if;
end if;
 
if porta_ctrl(1) = '0' then
ca1_edge <= ca1_fall;
else
ca1_edge <= ca1_rise;
end if;
 
end process;
 
---------------------------------
--
-- CA2 Edge detect
--
---------------------------------
ca2_input : process( clk, rst, ca2, ca2_del,
ca2_rise, ca2_fall, ca2_edge,
irqa2, porta_ctrl, porta_read )
begin
if clk'event and clk = '0' then
if rst = '1' then
ca2_del <= '0';
ca2_rise <= '0';
ca2_fall <= '0';
irqa2 <= '0';
else
ca2_del <= ca2;
ca2_rise <= (not ca2_del) and ca2;
ca2_fall <= ca2_del and (not ca2);
if porta_ctrl(5) = '0' and ca2_edge = '1' then
irqa2 <= '1';
elsif porta_read = '1' then
irqa2 <= '0';
else
irqa2 <= irqa2;
end if;
end if;
end if;
 
if porta_ctrl(4) = '0' then
ca2_edge <= ca2_fall;
else
ca2_edge <= ca2_rise;
end if;
end process;
 
---------------------------------
--
-- CA2 output control
--
---------------------------------
ca2_output : process( clk, rst, porta_ctrl, porta_read, ca1_edge, ca2_out )
begin
if clk'event and clk='0' then
if rst='1' then
ca2_out <= '0';
else
case porta_ctrl(5 downto 3) is
when "100" => -- read PA clears, CA1 edge sets
if porta_read = '1' then
ca2_out <= '0';
elsif ca1_edge = '1' then
ca2_out <= '1';
else
ca2_out <= ca2_out;
end if;
when "101" => -- read PA clears, E sets
ca2_out <= not porta_read;
when "110" => -- set low
ca2_out <= '0';
when "111" => -- set high
ca2_out <= '1';
when others => -- no change
ca2_out <= ca2_out;
end case;
end if;
end if;
end process;
 
---------------------------------
--
-- CA2 direction control
--
---------------------------------
ca2_direction : process( porta_ctrl, ca2, ca2_out )
begin
if porta_ctrl(5) = '0' then
ca2 <= 'Z';
else
ca2 <= ca2_out;
end if;
end process;
 
---------------------------------
--
-- direction control port b
--
---------------------------------
portb_direction : process ( portb_data, portb_ddr )
variable count : integer;
begin
for count in 0 to 7 loop
if portb_ddr(count) = '1' then
pb(count) <= portb_data(count);
else
pb(count) <= 'Z';
end if;
end loop;
end process;
 
---------------------------------
--
-- CB1 Edge detect
--
---------------------------------
cb1_input : process( clk, rst, cb1, cb1_del,
cb1_rise, cb1_fall, cb1_edge,
irqb1, portb_ctrl, portb_read )
begin
if clk'event and clk = '0' then
if rst = '1' then
cb1_del <= '0';
cb1_rise <= '0';
cb1_fall <= '0';
irqb1 <= '0';
else
cb1_del <= cb1;
cb1_rise <= (not cb1_del) and cb1;
cb1_fall <= cb1_del and (not cb1);
 
if cb1_edge = '1' then
irqb1 <= '1';
elsif portb_read = '1' then
irqb1 <= '0';
end if;
 
end if;
end if;
 
if portb_ctrl(1) = '0' then
cb1_edge <= cb1_fall;
else
cb1_edge <= cb1_rise;
end if;
end process;
 
---------------------------------
--
-- CB2 Edge detect
--
---------------------------------
cb2_input : process( clk, rst, cb2, cb2_del,
cb2_rise, cb2_fall, cb2_edge,
irqb2, portb_ctrl, portb_read )
begin
if clk'event and clk = '0' then
if rst = '1' then
cb2_del <= '0';
cb2_rise <= '0';
cb2_fall <= '0';
irqb2 <= '0';
else
cb2_del <= cb2;
cb2_rise <= (not cb2_del) and cb2;
cb2_fall <= cb2_del and (not cb2);
 
if portb_ctrl(5) = '0' and cb2_edge = '1' then
irqb2 <= '1';
elsif portb_read = '1' then
irqb2 <= '0';
end if;
 
end if;
end if;
 
if portb_ctrl(4) = '0' then
cb2_edge <= cb2_fall;
else
cb2_edge <= cb2_rise;
end if;
end process;
 
---------------------------------
--
-- CB2 output control
--
---------------------------------
cb2_output : process( clk, rst, portb_ctrl, portb_write, cb1_edge, cb2_out )
begin
if clk'event and clk='0' then
if rst='1' then
cb2_out <= '0';
else
case portb_ctrl(5 downto 3) is
when "100" => -- write PB clears, CA1 edge sets
if portb_write = '1' then
cb2_out <= '0';
elsif cb1_edge = '1' then
cb2_out <= '1';
end if;
when "101" => -- write PB clears, E sets
cb2_out <= not portb_write;
when "110" => -- set low
cb2_out <= '0';
when "111" => -- set high
cb2_out <= '1';
when others => -- no change
null;
end case;
end if;
end if;
end process;
 
---------------------------------
--
-- CB2 direction control
--
---------------------------------
cb2_direction : process( portb_ctrl, cb2, cb2_out )
begin
if portb_ctrl(5) = '0' then
cb2 <= 'Z';
else
cb2 <= cb2_out;
end if;
end process;
 
---------------------------------
--
-- IRQ control
--
---------------------------------
pia_irq : process( irqa1, irqa2, irqb1, irqb2, porta_ctrl, portb_ctrl )
begin
irqa <= (irqa1 and porta_ctrl(0)) or (irqa2 and porta_ctrl(3));
irqb <= (irqb1 and portb_ctrl(0)) or (irqb2 and portb_ctrl(3));
end process;
 
end pia_arch;
/cpu09_dummy_firq.vhd
1,28 → 1,51
-- $Id: cpu09_dummy_firq.vhd,v 1.1 2009-03-02 21:34:22 davidgb Exp $
--===========================================================================----
--==================================================================================--
-- --
-- cpu09_dummy_firq.vhd - Synthesizable 6809 instruction compatible VHDL CPU core --
-- --
--==================================================================================--
--
-- File name : cpu09_dummy_firq.vhd
--
-- Purpose : 6809 instruction compatible CPU core
-- This core is not bus cycle compatible with the original 6809
-- This version of the core has been patched to perform a RTI
-- after receiving an FIRQ interrupt.
-- This was done to try and diagnose a problem someone was having
-- with the FIRQ on a Williams Pinball Controller.
--
-- Dependencies : ieee.std_logic_1164
-- ieee.std_logic_unsigned
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- cpu09_dummy_firq.vhd is a 6809 instruction compatible CPU core written in VHDL.
-- This cpu09.vhd is not cycle compatible with the original 6809 CPU.
--
-- Copyright (C) 2002 - 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 --
-- --
--===========================================================================--
--
-- S Y N T H E Z I A B L E CPU09 - 6809 compatible CPU Core
--
-- www.OpenCores.Org - September 2003
-- This core adheres to the GNU public license
--
-- File name : cpu09.vhd
--
-- Purpose : 6809 CPU core
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
--
-- Uses : None
--
-- Author : John E. Kent
-- dilbert57@opencores.org
--
--===========================================================================----
--
-- Revision History:
--===========================================================================--
--
-- Version 0.1 - 26 June 2003 - John Kent
-- Added extra level in state stack
-- fixed some calls to the extended addressing state
139,22 → 162,22
-- 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 Dummy - 21st February 2008 -John Kent
-- patched FIRQ to return from interrupt
--
-- 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 Dummy - 21st February 2008 -John Kent
-- patched FIRQ to return from interrupt
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
389,7 → 412,7
-- State machine stack
--
----------------------------------
--state_stack_proc: process( clk, hold, state_stack, st_ctrl,
--state_stack_proc: process( clk, hold, state_stack, st_ctrl,
-- return_state, fetch_state )
state_stack_proc: process( clk, state_stack )
begin
1542,15 → 1565,15
addr_ctrl <= int_lo_ad;
dout_ctrl <= pc_lo_dout;
st_ctrl <= idle_st;
return_state <= fetch_state;
return_state <= fetch_state;
--
-- Patch to nobble FIRQ
-- Should cause a RTI on an FIRQ
--
-- Patch to nobble FIRQ
-- Should cause a RTI on an FIRQ
--
if iv = FIRQ_VEC then
if iv = FIRQ_VEC then
next_state <= rti_cc_state;
else
next_state <= fetch_state;
next_state <= fetch_state;
end if;
--
-- Here to fetch an instruction
1827,7 → 1850,7
up_ctrl <= latch_up;
sp_ctrl <= latch_sp;
end case;
when others =>
when others =>
null;
-- left_ctrl <= acca_left;
-- right_ctrl <= md_right;
2046,7 → 2069,7
up_ctrl <= latch_up;
sp_ctrl <= latch_sp;
end case;
when others =>
when others =>
null;
-- left_ctrl <= accb_left;
-- right_ctrl <= md_right;
3486,7 → 3509,7
next_state <= extended_state;
end case;
 
when others =>
when others =>
null;
-- op_ctrl <= latch_op;
-- acca_ctrl <= latch_acca;
5833,7 → 5856,7
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 =>
when others =>
null;
-- cond_true := (1 = 1);
end case;
9546,10 → 9569,10
if (nmi_req = '1') and (nmi_ack='0') then
iv_ctrl <= nmi_iv;
nmi_ctrl <= set_nmi;
--
-- John Kent 18th Feb 2008
--
-- John Kent 18th Feb 2008
--
-- next_state <= vect_hi_state;
-- next_state <= vect_hi_state;
next_state <= int_mask_state;
else
--
/trace.vhd
1,612 → 1,583
--===========================================================================--
--
-- S Y N T H E Z I A B L E Real Time Trace C O R E
--
-- www.OpenCores.Org - May 2003
-- This core adheres to the GNU public license
--
-- File name : trace.vhd
--
-- entity name : trace
--
-- Purpose : Implements a trace buffer
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
--
-- Author : John E. Kent
--
--===========================================================================----
--
-- Revision History:
--
-- Date: Revision Author
-- 19 June 2004 0.1 John Kent
--
--===========================================================================----
--
-- Register Memory Map
--
-- $00 - Address Comparitor High Byte
-- $01 - Address Comparitor Low byte
-- $02 - Data Comparitor
-- $03 - Control Comparitor
-- $04 - Address Qualifier High Byte
-- $05 - Address Qualifier Low byte
-- $06 - Data Qualifier
-- $07 - Control Qualifier
--
-- Address, Data and Control signals must match in the Comparitor registers
-- Matches are qualified by setting a bit in the Qualifier registers
--
-- Control Comparitor / Qualify (write)
-- b0 - r/w 1=read 0=write
-- b1 - vma 1=valid 0=invalid
-- b5 - trace 1=enable 0=disable
-- b6 - pre/post 1=before 0=after
-- b7 - irq output 1=match 0=mismatch
--
-- Control Qualifier Read
-- b7 - match flag
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity trace is
port (
clk : in std_logic;
rst : in std_logic;
rs : in std_logic; -- register select
bs : in std_logic; -- bank select
rw : in std_logic;
vma : in std_logic;
addr : in std_logic_vector(15 downto 0);
data_in : in std_logic_vector(7 downto 0);
reg_data_out : out std_logic_vector(7 downto 0);
buff_data_out : out std_logic_vector(7 downto 0);
cpu_data_in : in std_logic_vector(7 downto 0);
irq : out std_logic
);
end;
 
architecture trace_arch of trace is
 
signal clk_n : std_logic;
signal irq_out : std_logic;
signal qual_write : std_logic;
signal qual_read : std_logic;
--
-- bank select
--
signal bank_reg : std_logic_vector(7 downto 0);
 
--
-- Trigger registers
--
signal comp_addr_hi : std_logic_vector(7 downto 0);
signal comp_addr_lo : std_logic_vector(7 downto 0);
signal qual_addr_hi : std_logic_vector(7 downto 0);
signal qual_addr_lo : std_logic_vector(7 downto 0);
signal comp_data : std_logic_vector(7 downto 0);
signal qual_data : std_logic_vector(7 downto 0);
signal comp_ctrl : std_logic_vector(7 downto 0);
signal qual_ctrl : std_logic_vector(7 downto 0);
signal match_flag : std_logic;
 
--
-- Trace counter
--
signal trace_clk : std_logic;
signal trace_rst : std_logic;
signal trace_stb : std_logic;
signal trace_we : std_logic;
signal trace_count : std_logic_vector(9 downto 0);
signal trace_offset : std_logic_vector(9 downto 0);
 
signal trace_data_out_0 : std_logic_vector(7 downto 0);
signal trace_data_out_1 : std_logic_vector(7 downto 0);
signal trace_data_out_2 : std_logic_vector(7 downto 0);
signal trace_data_out_3 : std_logic_vector(7 downto 0);
signal trace_data_out_4 : std_logic_vector(7 downto 0);
signal trace_data_out_5 : std_logic_vector(7 downto 0);
 
signal buff_stb : std_logic_vector(5 downto 0);
signal buff_we : std_logic;
signal buff_addr : std_logic_vector(9 downto 0);
 
signal buff_data_out_0 : std_logic_vector(7 downto 0);
signal buff_data_out_1 : std_logic_vector(7 downto 0);
signal buff_data_out_2 : std_logic_vector(7 downto 0);
signal buff_data_out_3 : std_logic_vector(7 downto 0);
signal buff_data_out_4 : std_logic_vector(7 downto 0);
signal buff_data_out_5 : std_logic_vector(7 downto 0);
 
signal mux_stb : std_logic_vector(5 downto 0);
signal mux_we : std_logic;
signal mux_addr : std_logic_vector(9 downto 0);
 
signal ctrl_in : std_logic_vector(7 downto 0);
signal trigger : std_logic;
 
component ram1k
Port (
-- Port A is 8 bit
WB_CLK_I : in std_logic;
WB_RST_I : in std_logic;
WB_ADR_I : in std_logic_vector (9 downto 0);
WB_DAT_O : out std_logic_vector (7 downto 0);
WB_DAT_I : in std_logic_vector (7 downto 0);
WB_WE_I : in std_logic;
WB_STB_I : in std_logic
);
end component;
 
 
component BUFG
port (
i: in std_logic;
o: out std_logic
);
end component;
 
begin
 
--
-- Bank 1 = Trace buffer cpu control out
--
my_trace_buffer_1 : ram1k port map (
WB_CLK_I => clk,
WB_RST_I => rst,
WB_ADR_I => mux_addr,
WB_DAT_O => buff_data_out_1,
WB_DAT_I => ctrl_in(7 downto 0),
WB_WE_I => mux_we,
WB_STB_I => mux_stb(1)
);
 
--
-- Trace buffer 2 is cpu address out high
--
my_trace_buffer_2 : ram1k port map (
WB_CLK_I => clk,
WB_RST_I => rst,
WB_ADR_I => mux_addr,
WB_DAT_O => buff_data_out_2,
WB_DAT_I => addr(15 downto 8),
WB_WE_I => mux_we,
WB_STB_I => mux_stb(2)
);
 
--
-- Trace buffer 3 is cpu address out low
--
my_trace_buffer_3 : ram1k port map (
WB_CLK_I => clk,
WB_RST_I => rst,
WB_ADR_I => mux_addr,
WB_DAT_O => buff_data_out_3,
WB_DAT_I => addr(7 downto 0),
WB_WE_I => mux_we,
WB_STB_I => mux_stb(3)
);
 
--
-- Trace buffer 4 is cpu data out
--
my_trace_buffer_4 : ram1k port map (
WB_CLK_I => clk,
WB_RST_I => rst,
WB_ADR_I => mux_addr,
WB_DAT_O => buff_data_out_4,
WB_DAT_I => data_in(7 downto 0),
WB_WE_I => mux_we,
WB_STB_I => mux_stb(4)
);
 
--
-- Trace buffer 5 is cpu data in
--
my_trace_buffer_5 : ram1k port map (
WB_CLK_I => clk,
WB_RST_I => rst,
WB_ADR_I => mux_addr,
WB_DAT_O => buff_data_out_5,
WB_DAT_I => cpu_data_in(7 downto 0),
WB_WE_I => mux_we,
WB_STB_I => mux_stb(5)
);
 
 
--clk_buffer : BUFG port map(
-- i => clk_n,
-- o => trace_clk
-- );
 
--------------------------------
--
-- write page bank register
--
--------------------------------
bank_reg_write : process( clk, rst, rs, rw, data_in, bank_reg)
begin
if clk'event and clk = '0' then
if rst = '1' then
bank_reg <= "00000000";
else
if rs='1' and rw='0' then
bank_reg <= data_in;
else
bank_reg <= bank_reg;
end if;
end if;
end if;
end process;
 
 
--------------------------------
--
-- read page buffers
--
--------------------------------
 
buffer_read : process( bs, bank_reg,
buff_data_out_0, buff_data_out_1, buff_data_out_2, buff_data_out_3,
buff_data_out_4, buff_data_out_5 )
variable count : integer;
begin
for count in 0 to 5 loop
buff_stb(count) <= '0';
end loop;
 
case bank_reg(2 downto 0) is
when "000" =>
buff_stb(0) <= bs;
buff_data_out <= buff_data_out_0;
when "001" =>
buff_stb(1) <= bs;
buff_data_out <= buff_data_out_1;
when "010" =>
buff_stb(2) <= bs;
buff_data_out <= buff_data_out_2;
when "011" =>
buff_stb(3) <= bs;
buff_data_out <= buff_data_out_3;
when "100" =>
buff_stb(4) <= bs;
buff_data_out <= buff_data_out_4;
when "101" =>
buff_stb(5) <= bs;
buff_data_out <= buff_data_out_5;
when others =>
buff_data_out <= "00000000";
end case;
 
reg_data_out <= bank_reg;
 
end process;
 
--------------------------------
--
-- write control registers
--
--------------------------------
trace_write : process( clk, rst, bs, rw, addr, data_in, qual_write,
comp_addr_hi, comp_addr_lo, comp_data, comp_ctrl,
qual_addr_hi, qual_addr_lo, qual_data, qual_ctrl )
begin
if clk'event and clk = '0' then
if rst = '1' then
comp_addr_hi <= "00000000";
comp_addr_lo <= "00000000";
comp_data <= "00000000";
comp_ctrl <= "00000000";
qual_addr_hi <= "00000000";
qual_addr_lo <= "00000000";
qual_data <= "00000000";
qual_ctrl <= "00000000";
qual_write <= '0';
elsif buff_stb(0) = '1' and rw = '0' then
case addr(2 downto 0) is
when "000" =>
comp_addr_hi <= data_in;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
qual_write <= '0';
when "001" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= data_in;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
qual_write <= '0';
when "010" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= data_in;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
qual_write <= '0';
when "011" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= data_in;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
qual_write <= '0';
when "100" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= data_in;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
qual_write <= '0';
when "101" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= data_in;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
qual_write <= '0';
when "110" =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= data_in;
qual_ctrl <= qual_ctrl;
qual_write <= '0';
-- when "111" =>
when others =>
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= data_in;
qual_write <= '1';
end case;
else
comp_addr_hi <= comp_addr_hi;
comp_addr_lo <= comp_addr_lo;
comp_data <= comp_data;
comp_ctrl <= comp_ctrl;
qual_addr_hi <= qual_addr_hi;
qual_addr_lo <= qual_addr_lo;
qual_data <= qual_data;
qual_ctrl <= qual_ctrl;
qual_write <= '0';
end if;
end if;
end process;
 
--
-- trap data output mux
--
trace_read : process( buff_stb, rw, addr, qual_read,
comp_addr_hi, comp_addr_lo, comp_data, comp_ctrl,
qual_addr_hi, qual_addr_lo, qual_data, qual_ctrl,
match_flag )
begin
case addr(2 downto 0) is
when "000" =>
buff_data_out_0 <= comp_addr_hi;
qual_read <= '0';
when "001" =>
buff_data_out_0 <= comp_addr_lo;
qual_read <= '0';
when "010" =>
buff_data_out_0 <= comp_data;
qual_read <= '0';
when "011" =>
buff_data_out_0 <= comp_ctrl;
qual_read <= '0';
when "100" =>
buff_data_out_0 <= qual_addr_hi;
qual_read <= '0';
when "101" =>
buff_data_out_0 <= qual_addr_lo;
qual_read <= '0';
when "110" =>
buff_data_out_0 <= qual_data;
qual_read <= '0';
-- when "111" =>
when others =>
qual_read <= buff_stb(0) and rw;
buff_data_out_0(6 downto 0) <= qual_ctrl(6 downto 0);
buff_data_out_0(7) <= match_flag;
end case;
end process;
 
mux_proc : process( bs, rw,
trace_count, buff_addr,
trace_we, buff_we,
trace_stb, buff_stb )
begin
 
if bs='0' and rw='1' then
mux_addr <= trace_count;
mux_we <= trace_we;
mux_stb <= trace_stb & trace_stb & trace_stb & trace_stb & trace_stb & trace_stb;
else
mux_addr <= buff_addr;
mux_we <= buff_we;
mux_stb <= buff_stb;
end if;
 
end process;
 
--
-- Trigger hardware
--
trace_match : process( Clk, rst, rw, buff_stb, addr, vma, match_flag, data_in,
comp_addr_hi, comp_addr_lo, comp_data, comp_ctrl,
qual_addr_hi, qual_addr_lo, qual_data, qual_ctrl)
variable match : std_logic;
variable match_addr_hi : std_logic;
variable match_addr_lo : std_logic;
variable match_data : std_logic;
variable match_ctrl : std_logic;
 
begin
match_addr_hi :=
((comp_addr_hi(7) xor addr(15) ) and qual_addr_hi(7) ) or
((comp_addr_hi(6) xor addr(14) ) and qual_addr_hi(6) ) or
((comp_addr_hi(5) xor addr(13) ) and qual_addr_hi(5) ) or
((comp_addr_hi(4) xor addr(12) ) and qual_addr_hi(4) ) or
((comp_addr_hi(3) xor addr(11) ) and qual_addr_hi(3) ) or
((comp_addr_hi(2) xor addr(10) ) and qual_addr_hi(2) ) or
((comp_addr_hi(1) xor addr( 9) ) and qual_addr_hi(1) ) or
((comp_addr_hi(0) xor addr( 8) ) and qual_addr_hi(0) );
match_addr_lo :=
((comp_addr_lo(7) xor addr( 7) ) and qual_addr_lo(7) ) or
((comp_addr_lo(6) xor addr( 6) ) and qual_addr_lo(6) ) or
((comp_addr_lo(5) xor addr( 5) ) and qual_addr_lo(5) ) or
((comp_addr_lo(4) xor addr( 4) ) and qual_addr_lo(4) ) or
((comp_addr_lo(3) xor addr( 3) ) and qual_addr_lo(3) ) or
((comp_addr_lo(2) xor addr( 2) ) and qual_addr_lo(2) ) or
((comp_addr_lo(1) xor addr( 1) ) and qual_addr_lo(1) ) or
((comp_addr_lo(0) xor addr( 0) ) and qual_addr_lo(0) );
match_data :=
((comp_data(7) xor data_in(7)) and qual_data(7) ) or
((comp_data(6) xor data_in(6)) and qual_data(6) ) or
((comp_data(5) xor data_in(5)) and qual_data(5) ) or
((comp_data(4) xor data_in(4)) and qual_data(4) ) or
((comp_data(3) xor data_in(3)) and qual_data(3) ) or
((comp_data(2) xor data_in(2)) and qual_data(2) ) or
((comp_data(1) xor data_in(1)) and qual_data(1) ) or
((comp_data(0) xor data_in(0)) and qual_data(0) );
match_ctrl :=
((comp_ctrl(0) xor rw ) and qual_ctrl(0) ) or
((comp_ctrl(1) xor vma ) and qual_ctrl(1) );
 
match := not ( match_addr_hi or match_addr_lo or match_data or match_ctrl);
 
if clk'event and clk = '0' then
if rst = '1' then
match_flag <= '0';
elsif buff_stb(0) = '1' and rw = '0' then
match_flag <= '0';
else
if match = comp_ctrl(7) then
match_flag <= '1';
else
match_flag <= match_flag;
end if;
 
end if;
end if;
trigger <= match_flag;
end process;
 
trace_capture : process( clk, rst, qual_read, qual_write,
trigger, trace_stb, qual_ctrl, irq_out,
trace_count, trace_offset )
variable irq_tmp : std_logic;
begin
if clk'event and clk = '1' then
if rst = '1' then
trace_count <= "0000000000";
trace_offset <= "0000000000";
trace_stb <= qual_ctrl(6);
else
--
-- zero in bit 6 of the qalifier control register
-- means start capture after trigger point.
--
if qual_ctrl(6) = '0' then
 
if trace_stb = '0' then
trace_stb <= trigger;
irq_tmp := irq_out;
trace_offset <= trace_count;
else
if trace_count = trace_offset then
trace_stb <= '0';
irq_tmp := '1';
else
trace_stb <= trace_stb;
irq_tmp := irq_out;
end if;
trace_offset <= trace_offset;
end if;
 
if qual_read = '1' then
irq_out <= '0';
else
irq_out <= irq_tmp;
end if;
--
-- one in bit 6 of the qalifier control register
-- means finish capture at trigger point.
--
else
if trace_stb = '0' then
trace_stb <= qual_write;
trace_offset <= trace_offset;
irq_tmp := irq_out;
else
if trigger = '1' then
trace_offset <= trace_count;
trace_stb <= '0';
irq_tmp := '1';
else
trace_offset <= trace_offset;
trace_stb <= trace_stb;
irq_tmp := irq_out;
end if;
end if;
 
if qual_write = '1' then
irq_out <= '0';
else
irq_out <= irq_tmp;
end if;
end if;
trace_count <= trace_count + 1;
end if;
end if;
end process;
 
--
-- Tie up a few signals
--
process( clk, rst, addr, vma, rw, irq_out, trace_offset, qual_ctrl, trace_stb )
begin
trace_clk <= clk;
trace_rst <= rst;
trace_we <= trace_stb;
buff_addr <= addr(9 downto 0) + trace_offset;
buff_we <= '0';
irq <= irq_out and qual_ctrl(7);
ctrl_in(0) <= rw;
ctrl_in(1) <= vma;
ctrl_in(7 downto 2) <= "000000";
end process;
 
end trace_arch;
--===========================================================================--
-- --
-- Synthesizable Hardware Trace Capture --
-- --
--===========================================================================--
--
-- File name : trace.vhd
--
-- Entity name : trace
--
-- Purpose : Implements a hardware real-time trace buffer for system09.
-- Captures all the CPU bus cycles to a block RAM trace buffer.
-- A trigger condition may be used to start or stop a trace
-- capture. The trigger condition is determined by the address,
-- data and control, comparator and qualifier registers.
-- The comparator registers determine the level of the signals
-- to trigger on. The qualifier registers determine if the
-- comparison is to be made for that bit (qualifier bit set)
-- or not (qualifier bit cleared). The hardware trace capture
-- module has 9 x 8 bit registers and 5 trace buffers. Separate
-- chip selects are provided for the register bank and trace
-- buffer bank. The individual trace buffers are selected via
-- the bank select register. Trace buffers may be read by the
-- CPU but are only written to when tracing CPU bus cycles.
-- The lowest trace buffer address always points to the start
-- of the trace capture. This is achieved by adding an offset
-- to the buffer address which points to the last cycle captured.
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- Description : Register Memory Map
--
-- Register Bank(CS_R)
-- Base + $00 - Address Comparitor High Byte
-- Base + $01 - Address Comparitor Low byte
-- Base + $02 - Data Comparitor
-- Base + $03 - Control Comparitor
-- Base + $04 - Address Qualifier High Byte
-- Base + $05 - Address Qualifier Low byte
-- Base + $06 - Data Qualifier
-- Base + $07 - Control Qualifier
-- Base + $08 - Buffer Bank Select
-- Bits[2..0] Select Buffer Bank 0 to 4
--
-- Buffer Bank (CS_B)
-- Bank 0 - CPU Address high trace buffer
-- Bank 1 - CPU Address low trace buffer
-- Bank 2 - CPU Data output (write) trace buffer
-- Bank 3 - CPU Data input (read) trace buffer
-- Bank 4 - CPU Control signal trace buffer
--
-- Address, Data and Control signals
-- must match in the Comparitor registers
-- Matches are qualified by setting a bit
-- in the Qualifier registers
--
-- Control Comparitor / Control Qualify Write
-- b0 - r/w 1=read 0=write
-- b1 - vma 1=valid 0=invalid
-- b5 - trace 1=enable 0=disable
-- b6 - pre/post 1=before 0=after
-- b7 - irq output 1=match 0=mismatch
--
-- Control Qualifier Read
-- b7 - Interrupt Flag (unmasked)
--
-- Copyright (C) 2004 - 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 Date Author Description
--
-- 0.1 2004-06-19 John E. Kent Initial version
-- 0.2 2010-08-09 John E. Kent Updated header and added GPL
-- Added trigger on read or write data
-- (not just write data).
-- Rearranged register and buffer bank decoding
-- Added Generics for data width and buffer size
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity trace is
generic (
BUFF_SIZE : integer := 9; -- Buffer Address Bits (B4=9, B16=11)
DATA_WIDTH : integer := 8 -- Data Width
)
port (
clk : in std_logic; -- CPU bus clock
rst : in std_logic; -- Reset
cs_r : in std_logic; -- Register bank chip select
cs_b : in std_logic; -- Buffer bank chip select
rw : in std_logic; -- Read not Write
addr : in std_logic_vector((2*DATA_WIDTH)-1 downto 0); -- CPU address / Trace buffer address in
data_in : in std_logic_vector(DATA_WIDTH-1 downto 0); -- CPU data out (write)/ Trace data in
data_out : out std_logic_vector(DATA_WIDTH-1 downto 0); -- Trace data out (read)
irq : out std_logic;
cpu_vma : in std_logic; -- CPU VMA / Trace buffer VMA in
cpu_data_in : in std_logic_vector(DATA_WIDTH-1 downto 0) -- CPU read data in
);
end;
 
architecture trace_arch of trace is
 
--
-- Registers
--
signal comp_addr_hi : std_logic_vector(DATA_WIDTH-1 downto 0); -- Address High Comparator Reg
signal comp_addr_lo : std_logic_vector(DATA_WIDTH-1 downto 0); -- Address Low Comparator Reg
signal comp_data : std_logic_vector(DATA_WIDTH-1 downto 0); -- Data Comparator Reg
signal comp_ctrl : std_logic_vector(DATA_WIDTH-1 downto 0); -- Control Sig Comparator Reg
signal qual_addr_hi : std_logic_vector(DATA_WIDTH-1 downto 0); -- Address High Qualifier Reg
signal qual_addr_lo : std_logic_vector(DATA_WIDTH-1 downto 0); -- Address Low Qualifier Reg
signal qual_data : std_logic_vector(DATA_WIDTH-1 downto 0); -- Data Qualifier Reg
signal qual_ctrl : std_logic_vector(DATA_WIDTH-1 downto 0); -- Control Sig Qualifier Reg
signal bank_reg : std_logic_vector(DATA_WIDTH-1 downto 0); -- Trace Buffer Bank Select Reg
signal reg_data_out : std_logic_vector(DATA_WIDTH-1 downto 0); -- Register Data Output
 
--
-- Trace enable, counter and offset registers
--
signal trace_en : std_logic;
signal trace_count : std_logic_vector(BUFF_SIZE-1 downto 0);
signal trace_offset : std_logic_vector(BUFF_SIZE-1 downto 0);
 
--
-- Buffer address
--
signal buf_addr : std_logic_vector(BUFF_SIZE-1 downto 0);
 
--
-- Block RAM buffer Mux signals
--
signal mux_stb : std_logic;
signal mux_addr : std_logic_vector(BUFF_SIZE-1 downto 0);
signal mux_we : std_logic;
 
--
-- Block RAM trace buffer data outputs
--
signal buf_data_out_0 : std_logic_vector(DATA_WIDTH-1 downto 0);
signal buf_data_out_1 : std_logic_vector(DATA_WIDTH-1 downto 0);
signal buf_data_out_2 : std_logic_vector(DATA_WIDTH-1 downto 0);
signal buf_data_out_3 : std_logic_vector(DATA_WIDTH-1 downto 0);
signal buf_data_out_4 : std_logic_vector(DATA_WIDTH-1 downto 0);
signal buf_data_out : std_logic_vector(DATA_WIDTH-1 downto 0);
 
--
-- Various other signals
--
signal irq_out : std_logic; -- Interrupt Request signal (unmasked)
signal qual_write : std_logic; -- Qualifier Control Register Write Strobe
signal qual_read : std_logic; -- Qualifier Control Register Read Strobe
signal trigger : std_logic; -- Event Trigger derived from bus comparator
signal ctrl_in : std_logic_vector(7 downto 0);
 
--
-- Block RAM Trace buffer
-- For Spartan 2 these will be B4 RAMs ( 512 Bytes)
-- For Spartan 3 these will be B16 RAMs (2048 Bytes)
--
component trace_ram
Port (
WB_CLK_I : in std_logic;
WB_RST_I : in std_logic;
WB_ADR_I : in std_logic_vector (BUFF_SIZE-1 downto 0);
WB_DAT_O : out std_logic_vector (DATA_WIDTH-1 downto 0);
WB_DAT_I : in std_logic_vector (DATA_WIDTH-1 downto 0);
WB_WE_I : in std_logic;
WB_STB_I : in std_logic
);
end component;
 
--
-- Start of Architecture
--
begin
 
--
-- Instantiate (Port Map) Block RAM trace buffers
--
 
--
-- Bank 0 - Trace buffer for CPU address high bits
--
trace_buffer_0 : trace_ram port map (
WB_CLK_I => clk,
WB_RST_I => rst,
WB_ADR_I => mux_addr,
WB_DAT_O => buf_data_out_0,
WB_DAT_I => addr((2*DATA_WIDTH)-1 downto DATA_WIDTH),
WB_WE_I => mux_we,
WB_STB_I => mux_stb
);
 
--
-- Bank 1 - Trace buffer for CPU address low bits
--
trace_buffer_1 : trace_ram port map (
WB_CLK_I => clk,
WB_RST_I => rst,
WB_ADR_I => mux_addr,
WB_DAT_O => buf_data_out_1,
WB_DAT_I => addr(DATA_WIDTH-1 downto 0),
WB_WE_I => mux_we,
WB_STB_I => mux_stb
);
 
--
-- Bank 2 - Trace buffer for CPU data out (write)
--
trace_buffer_2 : trace_ram port map (
WB_CLK_I => clk,
WB_RST_I => rst,
WB_ADR_I => mux_addr,
WB_DAT_O => buf_data_out_2,
WB_DAT_I => data_in(DATA_WIDTH-1 downto 0),
WB_WE_I => mux_we,
WB_STB_I => mux_stb
);
 
--
-- Bank 3 - Trace buffer for CPU data in (read)
--
trace_buffer_3 : trace_ram port map (
WB_CLK_I => clk,
WB_RST_I => rst,
WB_ADR_I => mux_addr,
WB_DAT_O => buf_data_out_3,
WB_DAT_I => cpu_data_in(DATA_WIDTH-1 downto 0),
WB_WE_I => mux_we,
WB_STB_I => mux_stb
);
 
--
-- Bank 4 - Trace buffer for CPU control bits
--
trace_buffer_4 : trace_ram port map (
WB_CLK_I => clk,
WB_RST_I => rst,
WB_ADR_I => mux_addr,
WB_DAT_O => buf_data_out_4,
WB_DAT_I => ctrl_in(DATA_WIDTH-1 downto 0),
WB_WE_I => mux_we,
WB_STB_I => mux_stb
);
 
--------------------------------
--
-- Assign control signal input
--
--------------------------------
 
trace_ctrl_assign : process( irq_out, qual_ctrl, rw, cpu_vma )
begin
ctrl_in(0) <= rw;
ctrl_in(1) <= cpu_vma;
ctrl_in(7 downto 2) <= (others=>'0');
end process;
 
--------------------------------
--
-- Write Trace Registers
--
--------------------------------
 
trace_reg_write : process( clk, rst, cs_r, rw, addr, data_in )
begin
if clk'event and clk = '0' then
qual_write <= '0';
if rst = '1' then
comp_addr_hi <= (others=>'0');
comp_addr_lo <= (others=>'0');
comp_data <= (others=>'0');
comp_ctrl <= (others=>'0');
qual_addr_hi <= (others=>'0');
qual_addr_lo <= (others=>'0');
qual_data <= (others=>'0');
qual_ctrl <= (others=>'0');
bank_reg <= (others=>'0');
elsif cs_r = '1' and rw = '0' then
case addr(3 downto 0) is
when "0000" =>
comp_addr_hi <= data_in;
when "0001" =>
comp_addr_lo <= data_in;
when "0010" =>
comp_data <= data_in;
when "0011" =>
comp_ctrl <= data_in;
when "0100" =>
qual_addr_hi <= data_in;
when "0101" =>
qual_addr_lo <= data_in;
when "0110" =>
qual_data <= data_in;
when "0111" =>
qual_ctrl <= data_in;
qual_write <= '1';
when others =>
bank_reg <= data_in;
end case;
end if;
end if;
end process;
 
------------------------------------------
--
-- Read Trace Register (output mux)
--
------------------------------------------
trace_reg_read : process( addr, rw, cs_r,
comp_addr_hi, comp_addr_lo, comp_data, comp_ctrl,
qual_addr_hi, qual_addr_lo, qual_data, qual_ctrl,
bank_reg, irq_out )
begin
qual_read <= '0';
case addr(3 downto 0) is
when "0000" =>
reg_data_out <= comp_addr_hi;
when "0001" =>
reg_data_out <= comp_addr_lo;
when "0010" =>
reg_data_out <= comp_data;
when "0011" =>
reg_data_out <= comp_ctrl;
when "0100" =>
reg_data_out <= qual_addr_hi;
when "0101" =>
reg_data_out <= qual_addr_lo;
when "0110" =>
reg_data_out <= qual_data;
when "0111" =>
qual_read <= cs_r and rw;
reg_data_out(6 downto 0) <= qual_ctrl(6 downto 0);
reg_data_out(7) <= irq_out;
when others =>
reg_data_out <= bank_reg;
end case;
 
end process;
 
 
--------------------------------
--
-- Read Trace Buffers
--
--------------------------------
 
trace_buf_read : process( bank_reg, buf_data_out_0, buf_data_out_1,
buf_data_out_2, buf_data_out_3, buf_data_out_4 )
begin
case bank_reg(2 downto 0) is
when "000" =>
buf_data_out <= buf_data_out_0;
when "001" =>
buf_data_out <= buf_data_out_1;
when "010" =>
buf_data_out <= buf_data_out_2;
when "011" =>
buf_data_out <= buf_data_out_3;
when "100" =>
buf_data_out <= buf_data_out_4;
when others =>
buf_data_out <= (others=>'0');
end case;
end process;
 
--------------------------------
--
-- Read Registers or Buffers
--
--------------------------------
 
trace_read : process( cs_r, reg_data_out, buf_data_out )
begin
if cs_r = '1' then
data_out = reg_data_out;
else
data_out = buf_data_out;
else
end process;
 
 
------------------------------------------------------------------------
--
-- Multiplex the trace buffer between the trace capture and the CPU read
--
------------------------------------------------------------------------
 
trace_buf_mux : process( cs_b, trace_count, trace_en, buf_addr )
begin
if cs_b = '0' then
mux_addr <= trace_count;
mux_we <= '1';
mux_stb <= trace_en;
else
mux_addr <= buf_addr;
mux_we <= '0';
mux_stb <= '1';
end if;
 
end process;
 
------------------------------
--
-- Trigger comparator process
--
------------------------------
 
trace_trigger : process( clk, rst, cs_r, addr, rw, cpu_vma, data_in, cpu_data_in,
comp_addr_hi, comp_addr_lo, comp_data, comp_ctrl,
qual_addr_hi, qual_addr_lo, qual_data, qual_ctrl)
variable hit : std_logic;
variable miss_addr_hi : std_logic;
variable miss_addr_lo : std_logic;
variable miss_data_rd : std_logic;
variable miss_data_wr : std_logic;
variable miss_ctrl : std_logic;
 
begin
miss_addr_hi :=
((comp_addr_hi(7) xor addr(15) ) and qual_addr_hi(7) ) or
((comp_addr_hi(6) xor addr(14) ) and qual_addr_hi(6) ) or
((comp_addr_hi(5) xor addr(13) ) and qual_addr_hi(5) ) or
((comp_addr_hi(4) xor addr(12) ) and qual_addr_hi(4) ) or
((comp_addr_hi(3) xor addr(11) ) and qual_addr_hi(3) ) or
((comp_addr_hi(2) xor addr(10) ) and qual_addr_hi(2) ) or
((comp_addr_hi(1) xor addr( 9) ) and qual_addr_hi(1) ) or
((comp_addr_hi(0) xor addr( 8) ) and qual_addr_hi(0) );
miss_addr_lo :=
((comp_addr_lo(7) xor addr( 7) ) and qual_addr_lo(7) ) or
((comp_addr_lo(6) xor addr( 6) ) and qual_addr_lo(6) ) or
((comp_addr_lo(5) xor addr( 5) ) and qual_addr_lo(5) ) or
((comp_addr_lo(4) xor addr( 4) ) and qual_addr_lo(4) ) or
((comp_addr_lo(3) xor addr( 3) ) and qual_addr_lo(3) ) or
((comp_addr_lo(2) xor addr( 2) ) and qual_addr_lo(2) ) or
((comp_addr_lo(1) xor addr( 1) ) and qual_addr_lo(1) ) or
((comp_addr_lo(0) xor addr( 0) ) and qual_addr_lo(0) );
miss_data_wr :=
((comp_data(7) xor data_in(7)) and qual_data(7) ) or
((comp_data(6) xor data_in(6)) and qual_data(6) ) or
((comp_data(5) xor data_in(5)) and qual_data(5) ) or
((comp_data(4) xor data_in(4)) and qual_data(4) ) or
((comp_data(3) xor data_in(3)) and qual_data(3) ) or
((comp_data(2) xor data_in(2)) and qual_data(2) ) or
((comp_data(1) xor data_in(1)) and qual_data(1) ) or
((comp_data(0) xor data_in(0)) and qual_data(0) );
miss_data_rd :=
((comp_data(7) xor cpu_data_in(7)) and qual_data(7) ) or
((comp_data(6) xor cpu_data_in(6)) and qual_data(6) ) or
((comp_data(5) xor cpu_data_in(5)) and qual_data(5) ) or
((comp_data(4) xor cpu_data_in(4)) and qual_data(4) ) or
((comp_data(3) xor cpu_data_in(3)) and qual_data(3) ) or
((comp_data(2) xor cpu_data_in(2)) and qual_data(2) ) or
((comp_data(1) xor cpu_data_in(1)) and qual_data(1) ) or
((comp_data(0) xor cpu_data_in(0)) and qual_data(0) );
miss_ctrl :=
((comp_ctrl(0) xor rw ) and qual_ctrl(0) ) or
((comp_ctrl(1) xor cpu_vma ) and qual_ctrl(1) );
 
hit := not( miss_addr_hi or miss_addr_lo or (miss_data_rd and not(miss_ctrl) and rw) or (miss_data_wr and not(miss_ctrl) and not(rw)) or miss_ctrl);
trigger <= not(hit xor comp_ctrl(7));
 
end process;
 
-----------------------------------------
--
-- Trace buffer capture on event trigger
--
-----------------------------------------
 
trace_capture : process( clk, rst, addr, qual_write,
trigger, trace_en, qual_ctrl, irq_out,
trace_count, trace_offset )
begin
if clk'event and clk = '1' then
if rst = '1' then
trace_count <= (others=>'0');
trace_offset <= (others=>'0');
trace_en <= '0';
irq_out <= '0';
else
--
-- qualifier control register bit 6 = zero
-- means start capture after trigger point.
--
if qual_ctrl(6) = '0' then
 
--
-- Activate trace on a trigger condition
-- Deactive trace when the buffer is full
--
if trace_en = '0' then
trace_en <= trigger;
elsif trace_count = trace_offset then
trace_offset <= trace_count;
trace_en <= '0';
end if;
 
--
-- Set IRQ on trace buffer full
-- Reset IRQ on qualifier control register write
--
if qual_write = '1' then
irq_out <= '0';
elsif trace_count = trace_offset then
irq_out <= '1';
end if;
 
--
-- qualifier control register bit 6 = one
-- means finish capture at trigger point.
--
else
--
-- Activate trace on qualifier control write
-- Deactivate trace on a trigger condition
--
if trace_en = '0' then
trace_en <= qual_write;
elsif trigger = '1' then
trace_offset <= trace_count;
trace_en <= '0';
end if;
 
--
-- Set IRQ on a trigger condition
-- Reset IRQ on qualifier control register write
--
if qual_write = '1' then
irq_out <= '0';
elsif trigger = '1' then
irq_out <= '1';
end if;
 
end if;
 
trace_count <= trace_count + 1;
 
end if;
end if;
 
--
-- The IRQ output is qualified by the interrupt enable bit
-- (bit 7 of the qualifier control register)
--
irq <= irq_out and qual_ctrl(7);
 
--
-- Trace buffer is offset by start address
--
buf_addr <= addr(BUFF_SIZE-1 downto 0) + trace_offset;
 
end process;
 
end trace_arch;
/cpu09.vhd
1,5622 → 1,5640
-- $Id: cpu09.vhd,v 1.2 2008-03-14 15:52:46 dilbert57 Exp $
--===========================================================================----
--
-- S Y N T H E Z I A B L E CPU09 - 6809 compatible CPU Core
--
-- www.OpenCores.Org - September 2003
-- This core adheres to the GNU public license
--
-- File name : cpu09.vhd
--
-- Purpose : 6809 CPU core
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
--
-- Uses : None
--
-- Author : John E. Kent
-- dilbert57@opencores.org
--
--===========================================================================----
--
-- 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
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity cpu09 is
port (
clk: in std_logic;
rst: in std_logic;
rw: out std_logic;
vma: out std_logic;
address: out std_logic_vector(15 downto 0);
data_in: in std_logic_vector(7 downto 0);
data_out: out std_logic_vector(7 downto 0);
halt: in std_logic;
hold: in std_logic;
irq: in std_logic;
firq: in std_logic;
nmi: in std_logic
);
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,
-- 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, error_state,
--
andcc_state, orcc_state,
tfr_state, exg_state, exg1_state,
lea_state,
-- Multiplication
mul_state, mulea_state, muld_state,
mul0_state, mul1_state, mul2_state, mul3_state,
mul4_state, mul5_state, mul6_state, mul7_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_nmiirq_state, int_firq_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_maski_state, int_maskif_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 stack_type is array(2 downto 0) of state_type;
type st_type is (idle_st, push_st, pull_st );
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 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 );
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 state: state_type;
signal next_state: state_type;
signal saved_state: state_type;
signal return_state: state_type;
signal state_stack: stack_type;
signal st_ctrl: st_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 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
 
----------------------------------
--
-- State machine stack
--
----------------------------------
--state_stack_proc: process( clk, hold, state_stack, st_ctrl,
-- return_state, fetch_state )
state_stack_proc: process( clk, state_stack )
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
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 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;
when others =>
state_stack(0) <= state_stack(0);
state_stack(1) <= state_stack(1);
state_stack(2) <= state_stack(2);
end case;
end if;
end if;
saved_state <= state_stack(0);
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= '1' then
pc <= pc;
else
case pc_ctrl is
when reset_pc =>
pc <= "0000000000000000";
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 =>
-- when latch_pc =>
pc <= pc;
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= '1' then
ea <= ea;
else
case ea_ctrl is
when reset_ea =>
ea <= "0000000000000000";
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 =>
-- when latch_ea =>
ea <= ea;
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= '1' then
acca <= acca;
else
case acca_ctrl is
when reset_acca =>
acca <= "00000000";
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 =>
-- when latch_acca =>
acca <= acca;
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= '1' then
accb <= accb;
else
case accb_ctrl is
when reset_accb =>
accb <= "00000000";
when load_accb =>
accb <= out_alu(7 downto 0);
when pull_accb =>
accb <= data_in;
when others =>
-- when latch_accb =>
accb <= accb;
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= '1' then
xreg <= xreg;
else
case ix_ctrl is
when reset_ix =>
xreg <= "0000000000000000";
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 =>
-- when latch_ix =>
xreg <= xreg;
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= '1' then
yreg <= yreg;
else
case iy_ctrl is
when reset_iy =>
yreg <= "0000000000000000";
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 =>
-- when latch_iy =>
yreg <= yreg;
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= '1' then
sp <= sp;
nmi_enable <= nmi_enable;
else
case sp_ctrl is
when reset_sp =>
sp <= "0000000000000000";
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;
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;
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= '1' then
up <= up;
else
case up_ctrl is
when reset_up =>
up <= "0000000000000000";
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 =>
-- when latch_up =>
up <= up;
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= '1' then
md <= md;
else
case md_ctrl is
when reset_md =>
md <= "0000000000000000";
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 =>
-- when latch_md =>
md <= md;
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= '1' then
cc <= cc;
else
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 =>
-- when latch_cc =>
cc <= cc;
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= '1' then
dp <= dp;
else
case dp_ctrl is
when reset_dp =>
dp <= "00000000";
when load_dp =>
dp <= out_alu(7 downto 0);
when pull_dp =>
dp <= data_in;
when others =>
-- when latch_dp =>
dp <= dp;
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
--
----------------------------------
 
--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= '1' then
op_code <= op_code;
else
case op_ctrl is
when reset_op =>
op_code <= "00010010";
when fetch_op =>
op_code <= data_in;
when others =>
-- when latch_op =>
op_code <= op_code;
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= '1' then
pre_code <= pre_code;
else
case pre_ctrl is
when reset_pre =>
pre_code <= "00000000";
when fetch_pre =>
pre_code <= data_in;
when others =>
-- when latch_pre =>
pre_code <= pre_code;
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
state <= reset_state;
else
if hold = '1' then
state <= state;
else
state <= next_state;
end if;
end if;
end if;
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
--
------------------------------------
 
--nmi_handler : process( clk, rst, nmi, nmi_ack, nmi_req, nmi_enable )
nmi_handler : process( clk )
begin
if clk'event and clk='0' then
if rst='1' then
nmi_req <= '0';
else
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';
else
nmi_req <= nmi_req;
end if;
end if;
end if;
end if;
end process;
 
 
----------------------------------
--
-- Address output multiplexer
--
----------------------------------
 
addr_mux: process( addr_ctrl, pc, ea, up, sp, iv )
begin
case addr_ctrl is
when idle_ad =>
address <= "1111111111111111";
vma <= '0';
rw <= '1';
when fetch_ad =>
address <= pc;
vma <= '1';
rw <= '1';
when read_ad =>
address <= ea;
vma <= '1';
rw <= '1';
when write_ad =>
address <= ea;
vma <= '1';
rw <= '0';
when pushs_ad =>
address <= sp;
vma <= '1';
rw <= '0';
when pulls_ad =>
address <= sp;
vma <= '1';
rw <= '1';
when pushu_ad =>
address <= up;
vma <= '1';
rw <= '0';
when pullu_ad =>
address <= up;
vma <= '1';
rw <= '1';
when int_hi_ad =>
address <= "111111111111" & iv & "0";
vma <= '1';
rw <= '1';
when int_lo_ad =>
address <= "111111111111" & iv & "1";
vma <= '1';
rw <= '1';
when others =>
address <= "1111111111111111";
vma <= '0';
rw <= '1';
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);
when others =>
data_out <= "00000000";
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;
 
if (cc(CBIT) = '0') then
if( cc(HBIT) = '1' ) then
if valid_hi then
daa_reg := "00000110";
else
daa_reg := "01100110";
end if;
else
if valid_lo then
if valid_hi then
daa_reg := "00000000";
else
daa_reg := "01100000";
end if;
else
if( left(7 downto 4) <= 8 ) then
daa_reg := "00000110";
else
daa_reg := "01100110";
end if;
end if;
end if;
else
if ( cc(HBIT) = '1' )then
daa_reg := "01100110";
else
if valid_lo then
daa_reg := "01100000";
else
daa_reg := "01100110";
end if;
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,
irq, firq, nmi_req, nmi_ack, halt )
variable cond_true : boolean; -- variable used to evaluate coditional branches
begin
-- 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;
iv_ctrl <= latch_iv;
op_ctrl <= latch_op;
pre_ctrl <= latch_pre;
nmi_ctrl <= latch_nmi;
-- 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
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;
 
--
-- 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;
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;
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;
 
-- 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;
 
--
-- 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;
 
--
-- nop - No operation ( 1 byte )
-- 6809 => 2 cycles
-- cpu09 => 2 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 decode
--
when "0010" => -- nop
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;
 
when "1001" => -- daa
left_ctrl <= acca_left;
right_ctrl <= accb_right;
alu_ctrl <= alu_daa;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
next_state <= fetch_state;
 
when "1010" => -- orcc
-- increment the pc
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= orcc_state;
 
when "1100" => -- andcc
-- increment the pc
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= andcc_state;
 
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;
next_state <= fetch_state;
 
when "1110" => -- exg
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= exg_state;
 
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 others =>
-- increment the pc
pc_ctrl <= incr_pc;
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" =>
st_ctrl <= push_st;
return_state <= fetch_state;
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;
next_state <= fetch_state;
 
when "1011" => -- rti
next_state <= rti_cc_state;
 
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;
 
when "1101" => -- mul
next_state <= mul_state;
 
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;
 
when others =>
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;
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;
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 #
st_ctrl <= push_st;
return_state <= fetch_state;
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 =>
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;
 
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;
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 "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 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 "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 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 #
st_ctrl <= push_st;
return_state <= fetch_state;
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" | -- 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;
 
when others =>
null;
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;
next_state <= int_entire_state;
 
when others =>
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 #
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= imm16_state;
 
when others =>
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 =>
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 =>
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 =>
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 #
st_ctrl <= push_st;
return_state <= fetch_state;
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 =>
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 =>
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 =>
next_state <= fetch_state;
end case;
 
when others =>
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;
next_state <= int_entire_state;
when others =>
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 #
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= imm16_state;
when others =>
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 <
st_ctrl <= idle_st;
return_state <= fetch_state;
next_state <= dual_op_read16_state;
 
when others =>
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 =>
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 =>
next_state <= fetch_state;
end case;
 
when others =>
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
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;
next_state <= fetch_state;
when "1110" => -- jmp
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_ld16;
pc_ctrl <= load_pc;
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 =>
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;
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;
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;
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;
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;
st_ctrl <= pull_st;
next_state <= saved_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;
st_ctrl <= pull_st;
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;
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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;
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;
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;
else
cond_true := (1 = 1); -- lbra, lbsr, bsr
end if;
if cond_true then
pc_ctrl <= load_pc;
end if;
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;
st_ctrl <= pull_st;
next_state <= saved_state;
 
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;
--
st_ctrl <= pull_st;
next_state <= saved_state;
 
when andcc_state =>
-- AND CC with md
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_andcc;
cc_ctrl <= load_cc;
--
st_ctrl <= pull_st;
next_state <= saved_state;
 
when orcc_state =>
-- OR CC with md
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_orcc;
cc_ctrl <= load_cc;
--
st_ctrl <= pull_st;
next_state <= saved_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;
--
st_ctrl <= pull_st;
next_state <= saved_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
st_ctrl <= push_st;
return_state <= exg1_state;
next_state <= tfr_state;
 
when exg1_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;
next_state <= fetch_state;
 
when mul_state =>
-- move acca to md
left_ctrl <= acca_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_st16;
md_ctrl <= load_md;
next_state <= mulea_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;
next_state <= mul7_state;
 
when mul7_state =>
-- 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;
md_ctrl <= shiftl_md;
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;
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
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
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
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
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
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
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
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
next_state <= fetch_state;
end if;
 
when pshs_cc_state =>
-- idle sp
-- write cc
addr_ctrl <= pushs_ad;
dout_ctrl <= cc_dout;
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
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
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
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
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
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
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
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
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;
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
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
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
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
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
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
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
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
next_state <= fetch_state;
end if;
 
when pshu_cc_state =>
-- idle up
-- write cc
addr_ctrl <= pushu_ad;
dout_ctrl <= cc_dout;
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
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
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
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
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
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
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
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
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;
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;
next_state <= fetch_state;
 
--
-- here on IRQ or NMI interrupt
-- pre decrement the sp
-- Idle bus cycle
--
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;
 
--
-- 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 =>
-- set entire flag
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
--
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;
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;
 
--
-- 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
-- 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 =>
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;
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;
next_state <= fetch_state;
end if;
else
iv_ctrl <= reset_iv;
next_state <= sync_state;
end if;
end if;
 
 
when halt_state =>
if halt = '1' then
next_state <= halt_state;
else
next_state <= fetch_state;
end if;
 
when others => -- halt on undefine states
next_state <= error_state;
end case;
end process;
 
end rtl;
--===========================================================================--
-- --
-- Synthesizable 6809 instruction compatible VHDL CPU core --
-- --
--===========================================================================--
--
-- File name : cpu09.vhd
--
-- Entity name : cpu09
--
-- Purpose : 6809 instruction compatible CPU core written in VHDL
-- 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
--
--
-- 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
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity cpu09 is
port (
clk : in std_logic;
rst : in std_logic;
vma : out std_logic;
addr : out std_logic_vector(15 downto 0);
rw : out std_logic;
data_out : out std_logic_vector(7 downto 0);
data_in : in std_logic_vector(7 downto 0);
irq : in std_logic;
firq : in std_logic;
nmi : in std_logic;
halt : in std_logic;
hold : in std_logic
);
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,
-- 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, error_state,
--
andcc_state, orcc_state,
tfr_state, exg_state, exg1_state,
lea_state,
-- Multiplication
mul_state, mulea_state, muld_state,
mul0_state, mul1_state, mul2_state, mul3_state,
mul4_state, mul5_state, mul6_state, mul7_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_nmiirq_state, int_firq_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_maski_state, int_maskif_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 stack_type is array(2 downto 0) of state_type;
type st_type is (idle_st, push_st, pull_st );
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 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 );
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 state: state_type;
signal next_state: state_type;
signal saved_state: state_type;
signal return_state: state_type;
signal state_stack: stack_type;
signal st_ctrl: st_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 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
 
----------------------------------
--
-- State machine stack
--
----------------------------------
--state_stack_proc: process( clk, hold, state_stack, st_ctrl,
-- return_state, fetch_state )
state_stack_proc: process( clk, state_stack )
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
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 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;
when others =>
state_stack(0) <= state_stack(0);
state_stack(1) <= state_stack(1);
state_stack(2) <= state_stack(2);
end case;
end if;
end if;
saved_state <= state_stack(0);
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= '1' then
pc <= pc;
else
case pc_ctrl is
when reset_pc =>
pc <= "0000000000000000";
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 =>
-- when latch_pc =>
pc <= pc;
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= '1' then
ea <= ea;
else
case ea_ctrl is
when reset_ea =>
ea <= "0000000000000000";
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 =>
-- when latch_ea =>
ea <= ea;
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= '1' then
acca <= acca;
else
case acca_ctrl is
when reset_acca =>
acca <= "00000000";
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 =>
-- when latch_acca =>
acca <= acca;
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= '1' then
accb <= accb;
else
case accb_ctrl is
when reset_accb =>
accb <= "00000000";
when load_accb =>
accb <= out_alu(7 downto 0);
when pull_accb =>
accb <= data_in;
when others =>
-- when latch_accb =>
accb <= accb;
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= '1' then
xreg <= xreg;
else
case ix_ctrl is
when reset_ix =>
xreg <= "0000000000000000";
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 =>
-- when latch_ix =>
xreg <= xreg;
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= '1' then
yreg <= yreg;
else
case iy_ctrl is
when reset_iy =>
yreg <= "0000000000000000";
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 =>
-- when latch_iy =>
yreg <= yreg;
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= '1' then
sp <= sp;
nmi_enable <= nmi_enable;
else
case sp_ctrl is
when reset_sp =>
sp <= "0000000000000000";
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;
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;
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= '1' then
up <= up;
else
case up_ctrl is
when reset_up =>
up <= "0000000000000000";
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 =>
-- when latch_up =>
up <= up;
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= '1' then
md <= md;
else
case md_ctrl is
when reset_md =>
md <= "0000000000000000";
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 =>
-- when latch_md =>
md <= md;
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= '1' then
cc <= cc;
else
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 =>
-- when latch_cc =>
cc <= cc;
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= '1' then
dp <= dp;
else
case dp_ctrl is
when reset_dp =>
dp <= "00000000";
when load_dp =>
dp <= out_alu(7 downto 0);
when pull_dp =>
dp <= data_in;
when others =>
-- when latch_dp =>
dp <= dp;
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
--
----------------------------------
 
--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= '1' then
op_code <= op_code;
else
case op_ctrl is
when reset_op =>
op_code <= "00010010";
when fetch_op =>
op_code <= data_in;
when others =>
-- when latch_op =>
op_code <= op_code;
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= '1' then
pre_code <= pre_code;
else
case pre_ctrl is
when reset_pre =>
pre_code <= "00000000";
when fetch_pre =>
pre_code <= data_in;
when others =>
-- when latch_pre =>
pre_code <= pre_code;
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
state <= reset_state;
else
if hold = '1' then
state <= state;
else
state <= next_state;
end if;
end if;
end if;
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
--
------------------------------------
 
--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
case addr_ctrl is
when idle_ad =>
vma <= '0';
addr <= "1111111111111111";
rw <= '1';
when fetch_ad =>
vma <= '1';
addr <= pc;
rw <= '1';
when read_ad =>
vma <= '1';
addr <= ea;
rw <= '1';
when write_ad =>
vma <= '1';
addr <= ea;
rw <= '0';
when pushs_ad =>
vma <= '1';
addr <= sp;
rw <= '0';
when pulls_ad =>
vma <= '1';
addr <= sp;
rw <= '1';
when pushu_ad =>
vma <= '1';
addr <= up;
rw <= '0';
when pullu_ad =>
vma <= '1';
addr <= up;
rw <= '1';
when int_hi_ad =>
vma <= '1';
addr <= "111111111111" & iv & "0";
rw <= '1';
when int_lo_ad =>
vma <= '1';
addr <= "111111111111" & iv & "1";
rw <= '1';
when others =>
vma <= '0';
addr <= "1111111111111111";
rw <= '1';
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);
when others =>
data_out <= "00000000";
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;
 
if (cc(CBIT) = '0') then
if( cc(HBIT) = '1' ) then
if valid_hi then
daa_reg := "00000110";
else
daa_reg := "01100110";
end if;
else
if valid_lo then
if valid_hi then
daa_reg := "00000000";
else
daa_reg := "01100000";
end if;
else
if( left(7 downto 4) <= 8 ) then
daa_reg := "00000110";
else
daa_reg := "01100110";
end if;
end if;
end if;
else
if ( cc(HBIT) = '1' )then
daa_reg := "01100110";
else
if valid_lo then
daa_reg := "01100000";
else
daa_reg := "01100110";
end if;
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,
irq, firq, nmi_req, nmi_ack, halt )
variable cond_true : boolean; -- variable used to evaluate coditional branches
begin
-- 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;
iv_ctrl <= latch_iv;
op_ctrl <= latch_op;
pre_ctrl <= latch_pre;
nmi_ctrl <= latch_nmi;
-- 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
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;
 
--
-- 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;
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;
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;
 
-- 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;
 
--
-- 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;
 
--
-- nop - No operation ( 1 byte )
-- 6809 => 2 cycles
-- cpu09 => 2 cycles
-- 1 op=(pc) / pc=pc+1
-- 2 decode
--
when "0010" => -- nop
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;
 
when "1001" => -- daa
left_ctrl <= acca_left;
right_ctrl <= accb_right;
alu_ctrl <= alu_daa;
cc_ctrl <= load_cc;
acca_ctrl <= load_acca;
next_state <= fetch_state;
 
when "1010" => -- orcc
-- increment the pc
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= orcc_state;
 
when "1100" => -- andcc
-- increment the pc
pc_ctrl <= incr_pc;
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= andcc_state;
 
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;
next_state <= fetch_state;
 
when "1110" => -- exg
-- increment the pc
pc_ctrl <= incr_pc;
next_state <= exg_state;
 
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 others =>
-- increment the pc
pc_ctrl <= incr_pc;
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" =>
st_ctrl <= push_st;
return_state <= fetch_state;
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;
next_state <= fetch_state;
 
when "1011" => -- rti
next_state <= rti_cc_state;
 
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;
 
when "1101" => -- mul
next_state <= mul_state;
 
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;
 
when others =>
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;
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;
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 #
st_ctrl <= push_st;
return_state <= fetch_state;
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 =>
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;
 
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;
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 "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 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 "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 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 #
st_ctrl <= push_st;
return_state <= fetch_state;
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" | -- 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;
 
when others =>
null;
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;
next_state <= int_entire_state;
 
when others =>
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 #
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= imm16_state;
 
when others =>
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 =>
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 =>
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 =>
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 #
st_ctrl <= push_st;
return_state <= fetch_state;
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 =>
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 =>
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 =>
next_state <= fetch_state;
end case;
 
when others =>
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;
next_state <= int_entire_state;
when others =>
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 #
st_ctrl <= push_st;
return_state <= fetch_state;
next_state <= imm16_state;
when others =>
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 <
st_ctrl <= idle_st;
return_state <= fetch_state;
next_state <= dual_op_read16_state;
 
when others =>
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 =>
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 =>
next_state <= fetch_state;
end case;
 
when others =>
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
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;
next_state <= fetch_state;
when "1110" => -- jmp
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_ld16;
pc_ctrl <= load_pc;
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 =>
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;
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;
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;
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;
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;
st_ctrl <= pull_st;
next_state <= saved_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;
st_ctrl <= pull_st;
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;
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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
st_ctrl <= pull_st;
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;
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;
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;
else
cond_true := (1 = 1); -- lbra, lbsr, bsr
end if;
if cond_true then
pc_ctrl <= load_pc;
end if;
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;
st_ctrl <= pull_st;
next_state <= saved_state;
 
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;
--
st_ctrl <= pull_st;
next_state <= saved_state;
 
when andcc_state =>
-- AND CC with md
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_andcc;
cc_ctrl <= load_cc;
--
st_ctrl <= pull_st;
next_state <= saved_state;
 
when orcc_state =>
-- OR CC with md
left_ctrl <= md_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_orcc;
cc_ctrl <= load_cc;
--
st_ctrl <= pull_st;
next_state <= saved_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;
--
st_ctrl <= pull_st;
next_state <= saved_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
st_ctrl <= push_st;
return_state <= exg1_state;
next_state <= tfr_state;
 
when exg1_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;
next_state <= fetch_state;
 
when mul_state =>
-- move acca to md
left_ctrl <= acca_left;
right_ctrl <= zero_right;
alu_ctrl <= alu_st16;
md_ctrl <= load_md;
next_state <= mulea_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;
next_state <= mul7_state;
 
when mul7_state =>
-- 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;
md_ctrl <= shiftl_md;
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
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
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
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
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
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
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
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
next_state <= fetch_state;
end if;
 
when pshs_cc_state =>
-- idle sp
-- write cc
addr_ctrl <= pushs_ad;
dout_ctrl <= cc_dout;
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
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
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
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
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
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
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
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
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;
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
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
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
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
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
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
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
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
next_state <= fetch_state;
end if;
 
when pshu_cc_state =>
-- idle up
-- write cc
addr_ctrl <= pushu_ad;
dout_ctrl <= cc_dout;
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
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
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
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
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
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
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
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
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;
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;
next_state <= fetch_state;
 
--
-- here on IRQ or NMI interrupt
-- pre decrement the sp
-- Idle bus cycle
--
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;
 
--
-- 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 =>
-- set entire flag
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
--
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;
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;
 
--
-- 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
-- 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 =>
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;
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;
next_state <= fetch_state;
end if;
else
iv_ctrl <= reset_iv;
next_state <= sync_state;
end if;
end if;
 
 
when halt_state =>
if halt = '1' then
next_state <= halt_state;
else
next_state <= fetch_state;
end if;
 
when others => -- halt on undefine states
next_state <= error_state;
end case;
end process;
 
end rtl;
/keyboard.vhd
1,36 → 1,116
---------------------------------------------------------------------------------------
--===========================================================================--
-- --
-- keyboard.vhd - Synthesizable Interface to PS/2 Keyboard Module --
-- --
--===========================================================================--
--
-- Author: John Kent
-- Date : April 2, 2004
-- Interface to John Clayton's PS2 keyboard
-- File name : keyboard.vhd
--
-- Entity name : keyboard
--
---------------------------------------------------------------------------------------
--
-- 7th Februaury 2007 - John Kent
-- Added Generics for Keyboard Timing
--
-- Purpose : Implements a CPU interface to John Clayton's PS/2 Keyboard
--
-- Dependencies : ieee.std_logic_1164
-- ieee.std_logic_arith
-- ieee.std_logic_unsigned
-- ieee.numeric_std
-- unisim.vcomponents
--
-- Uses : ps2_keyboard_interface
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- Registers :
--
-- IO address + 0 read - Status Register
--
-- Bit[0] - RX Data Ready
-- Bit[1] - TX Data Empty
-- Bit[2] - Extended
-- Bit[3] - Released
-- Bit[4] - Shift On
-- Bit[5] - Error (no keyboard acknowledge received)
-- Bit[6] - TX Interrupt Flag
-- Bit[7] - RX Interrupt Flag
--
-- IO address + 0 write - Control Register
--
-- Bit[0] - Undefined
-- Bit[1] - Undefined
-- Bit[2] - Undefined
-- Bit[3] - Undefined
-- Bit[4] - Undefined
-- Bit[5] - Undefined
-- Bit[6] - TX Interrupt Enable
-- Bit[7] - RX Interrupt Enable
--
-- IO address + 1 read - Receive Data Register
--
-- IO address + 1 write - Transmit Data Register
--
-- Copyright (C) 2004 - 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 Author Date Description
-- 0.1 John Kent 2nd April 2004 Interface to John Clayton's PS2 keyboard
-- 0.2 John Kent 7th Februaury 2007 Added Generics for Keyboard Timing
-- 0.3 John Kent 30th May 2010 Updated Header, added unisim library
-- 0.4 John Kent 17th June 2010 Cleaned up signal names,
-- added TX interrupt enable
-- Modified assignment of status register
-- Revised hanshake control and input registers
--
 
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
library unisim;
use unisim.vcomponents.all;
 
 
entity keyboard is
generic (
KBD_Clock_Frequency : integer
KBD_CLK_FREQ : integer
);
 
port(
port(
--
-- CPU Interface Signals
--
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
addr : in std_logic;
rw : in std_logic;
addr : in std_logic;
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
irq : out std_logic;
irq : out std_logic;
--
-- Keyboard Interface Signals
--
kbd_clk : inout std_logic;
kbd_data : inout std_logic
);
38,126 → 118,149
 
architecture rtl of keyboard is
 
constant Clock_Frequency_MHz : integer := KBD_Clock_Frequency / 1000000;
constant CLK_FREQ_MHZ : integer := KBD_CLK_FREQ / 1000000;
 
signal kbd_stat : std_logic_vector(7 downto 0);
signal kbd_ctrl : std_logic_vector(7 downto 6);
signal kbd_ascii_code : std_logic_vector(7 downto 0);
signal kbd_status : std_logic_vector(7 downto 0);
signal kbd_control : std_logic_vector(7 downto 0);
signal kbd_rx_data : std_logic_vector(7 downto 0);
signal kbd_tx_data : std_logic_vector(7 downto 0);
signal kbd_read : std_logic;
signal kbd_write : std_logic;
signal kbd_write_ack : std_logic;
signal kbd_data_ready : std_logic; -- => kbd_status(0)
signal kbd_data_empty : std_logic; -- => kbd_status(1)
signal kbd_extended : std_logic; -- => kbd_status(2)
signal kbd_released : std_logic; -- => kbd_status(3)
signal kbd_shift_on : std_logic; -- => kbd_status(4)
signal kbd_error : std_logic; -- => kbd_status(5) (No receive acknowledge)
 
component ps2_keyboard_interface
component ps2_keyboard
generic (
Frequency_MHz : integer := Clock_Frequency_MHz
CLK_FREQ_MHZ : integer := CLK_FREQ_MHZ
);
 
port(
clk : in std_logic;
reset : in std_logic;
ps2_clk : inout std_logic;
ps2_data : inout std_logic;
rx_data : out std_logic_vector(7 downto 0);
rx_read : in std_logic;
rx_data_ready : out std_logic;
rx_extended : out std_logic;
rx_released : out std_logic;
rx_shift_key_on : out std_logic;
-- rx_scan_code : out std_logic_vector(7 downto 0);
rx_ascii : out std_logic_vector(7 downto 0);
rx_data_ready : out std_logic; -- rx_read_o
rx_read : in std_logic; -- rx_read_ack_i
rx_shift_on : out std_logic;
tx_data : in std_logic_vector(7 downto 0);
tx_write : in std_logic;
tx_write_ack : out std_logic;
tx_error_no_keyboard_ack : out std_logic
tx_data_empty : out std_logic;
tx_error : out std_logic;
ps2_clk : inout std_logic;
ps2_data : inout std_logic
);
end component;
 
begin
 
my_ps2_keyboard_interface : ps2_keyboard_interface
my_ps2_keyboard : ps2_keyboard
generic map (
Frequency_MHz => Clock_Frequency_MHz
CLK_FREQ_MHZ => CLK_FREQ_MHz
)
 
port map(
clk => clk,
reset => rst,
ps2_clk => kbd_clk,
ps2_data => kbd_data,
rx_extended => kbd_stat(2),
rx_released => kbd_stat(3),
rx_shift_key_on => kbd_stat(4),
rx_ascii => kbd_ascii_code,
rx_data_ready => kbd_stat(0),
rx_data => kbd_rx_data,
rx_read => kbd_read,
rx_data_ready => kbd_data_ready,
rx_extended => kbd_extended,
rx_released => kbd_released,
rx_shift_on => kbd_shift_on,
tx_data => kbd_tx_data,
tx_write => kbd_write,
tx_write_ack => kbd_write_ack,
tx_error_no_keyboard_ack => kbd_stat(5)
tx_data_empty => kbd_data_empty,
tx_error => kbd_error,
ps2_clk => kbd_clk,
ps2_data => kbd_data
);
 
--
-- Keyboard Read strobe
--
keyboard_read : process( clk, rst, cs, rw, kbd_data_ready )
begin
if rst = '1' then
kbd_read <= '0';
elsif( clk'event and clk='0' ) then
if( cs = '1' and addr = '1' and rw = '1' ) then
kbd_read <= '1';
elsif kbd_data_ready = '1' then
kbd_read <= '0';
end if;
end if;
end process;
 
--
-- Keyboard Write strobe
--
keyboard_write : process( clk, rst, cs, rw, addr,
kbd_write, kbd_data_empty )
begin
if rst = '1' then
kbd_write <= '0';
elsif( clk'event and clk='0' ) then
if( cs = '1' and addr = '1' and rw = '0' ) then
kbd_write <= '1';
elsif kbd_data_empty = '1' then
kbd_write <= '0';
end if;
end if;
end process;
 
keyboard_strobe : process( clk, rst, cs, rw, kbd_stat )
begin
if( rst = '1' ) then
kbd_read <= '0';
elsif( clk'event and clk='0' ) then
if( cs='1' and rw='1' and addr='1' ) then
kbd_read <= '1';
elsif( kbd_stat(0)='1' ) then
kbd_read <= '0';
else
kbd_read <= kbd_read;
end if;
end if;
end process;
--
-- Keyboard register input
--
keyboard_in : process( clk, rst, cs, rw, addr, data_in, kbd_rx_data )
begin
if rst = '1' then
kbd_control <= (others => '0');
kbd_tx_data <= (others => '0');
elsif( clk'event and clk='0' ) then
if( cs = '1' and rw = '0' ) then
if addr = '0' then
kbd_control <= data_in;
else
kbd_tx_data <= data_in;
end if;
end if;
end if;
end process;
 
--
-- read keyboard registers
--
keyboard_read : process( addr, kbd_ascii_code, kbd_stat )
begin
if( addr = '1' ) then
data_out <= kbd_ascii_code;
else
data_out <= kbd_stat;
end if;
end process;
 
--
-- Write to keyboard register
--
keyboard_write : process( clk, rst, cs, rw, addr, data_in, kbd_tx_data,
kbd_write, kbd_write_ack )
begin
if(rst = '1' ) then
kbd_ctrl <= "00";
kbd_tx_data <= "00000000";
kbd_write <= '0';
elsif( clk'event and clk='0' ) then
if( cs='1' and rw='0' ) then
if( addr='1' ) then
kbd_tx_data <= data_in;
kbd_ctrl <= kbd_ctrl;
kbd_write <= '1';
else
kbd_tx_data <= kbd_tx_data;
kbd_ctrl <= data_in(7 downto 6);
kbd_write <= kbd_write;
end if;
elsif( kbd_write_ack='1' ) then
kbd_write <= '0';
else
kbd_write <= kbd_write;
end if;
kbd_stat(1) <= not kbd_write;
end if;
end process;
 
keyboard_interrupt : process( kbd_ctrl, kbd_stat )
begin
kbd_stat(6) <= kbd_ctrl(6);
kbd_stat(7) <= kbd_ctrl(7) and kbd_stat(0);
irq <= kbd_stat(7);
end process;
--
-- Keyboard register output
--
keyboard_out : process( addr, kbd_rx_data, kbd_status )
begin
if( addr = '0' ) then
data_out <= kbd_status;
else
data_out <= kbd_rx_data;
end if;
end process;
 
--
-- Assign Keyboard Status bits
--
keyboard_status : process( kbd_data_ready, kbd_data_empty,
kbd_extended, kbd_released, kbd_shift_on, kbd_error,
kbd_control)
begin
kbd_status(0) <= kbd_data_ready;
kbd_status(1) <= kbd_data_empty;
kbd_status(2) <= kbd_extended;
kbd_status(3) <= kbd_released;
kbd_status(4) <= kbd_shift_on;
kbd_status(5) <= kbd_error;
kbd_status(6) <= kbd_control(6) and kbd_data_empty; -- TX Interrupt Flag
kbd_status(7) <= kbd_control(7) and kbd_data_ready; -- RX Interrupt Flag
irq <= kbd_status(7) or kbd_status(6);
end process;
 
end rtl;
 
/mul32.vhd
1,35 → 1,73
--===========================================================================--
--===========================================================================--
-- --
-- mul32.vhd - Synthesizable 32 bit Multiplier Register for Spartan 3/3E --
-- --
--===========================================================================--
--
-- S Y N T H E Z I A B L E Dynamic Address Translation Registers
-- File name : mul32.vhd
--
-- Entity name : mul32
--
--===========================================================================--
--
-- This core adheres to the GNU public license
--
-- File name : mul32.vhd
--
-- entity name : mul32
--
-- Purpose : Implements a 32 bit x 32 bit hardware multiplier
-- with 64 bit reset
-- R/W Registers 0 to 3 are the left input MSB first
-- R/W Registers 4 to 7 are the right input MSB first
-- RO Registers 8 to 15 are the 64 bit result
-- Purpose : Implements a 32 bit x 32 bit hardware multiplier register
-- with 64 bit result. Consists of 16 x 8 bit registers.
-- Designed for Spartan 3/3E with 18 x 18 bit multiplier blocks.
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
-- 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 left input Most Significant Byte
-- 1 R/W left input
-- 2 R/W left input
-- 3 R/W left input Least Significant Byte
-- 4 R/W right input Most Significant Byte
-- 5 R/W right input
-- 6 R/W right input
-- 7 R/W right 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) 2008 - 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 Author Date Description
--
-- 0.1 John Kent 2008-09-07 Initial version
--
-- 0.2 John Kent 2010-06-17 Header & GPL added
--
-- Author : John E. Kent
--
--===========================================================================----
--
-- Revision History:
--
-- Date Revision Author
-- 7th Sep 2008 0.1 John Kent
--
--
--
 
library ieee;
use ieee.std_logic_1164.all;
48,10 → 86,10
dato : out std_logic_vector(7 downto 0));
end entity;
 
architecture rtl of mul32 is
architecture rtl of mul32 is
--
-- registers
--
-- registers
--
signal mul_reg0 : std_logic_vector(7 downto 0);
signal mul_reg1 : std_logic_vector(7 downto 0);
signal mul_reg2 : std_logic_vector(7 downto 0);
115,7 → 153,7
end if;
end if;
end process;
 
 
---------------------------------
--
-- Read Multiplier Registers
166,48 → 204,48
end case;
end process;
 
 
---------------------------------
--
-- Perform 32 x 32 multiply
--
---------------------------------
 
 
my_mul32 : process(
mul_reg0, mul_reg1, mul_reg2, mul_reg3,
mul_reg4, mul_reg5, mul_reg6, mul_reg7
)
variable mul_left_hi : std_logic_vector(17 downto 0);
variable mul_left_lo : std_logic_vector(17 downto 0);
variable mul_right_hi : std_logic_vector(17 downto 0);
variable mul_right_lo : std_logic_vector(17 downto 0);
variable mul_out_0 : std_logic_vector(35 downto 0);
variable mul_out_1 : std_logic_vector(35 downto 0);
variable mul_out_2 : std_logic_vector(35 downto 0);
variable mul_out_3 : std_logic_vector(35 downto 0);
variable mul_out : std_logic_vector(63 downto 0);
begin
mul_left_hi := "00" & mul_reg0 & mul_reg1;
mul_left_lo := "00" & mul_reg2 & mul_reg3;
mul_right_hi := "00" & mul_reg4 & mul_reg5;
mul_right_lo := "00" &mul_reg6 & mul_reg7;
mul_out_0 := mul_left_hi * mul_right_hi;
mul_out_1 := mul_left_hi * mul_right_lo;
mul_out_2 := mul_left_lo * mul_right_hi;
mul_out_3 := mul_left_lo * mul_right_lo;
mul_out := (mul_out_0( 31 downto 0) & "0000000000000000" & "0000000000000000") +
("0000000000000000" & mul_out_1( 31 downto 0) & "0000000000000000") +
("0000000000000000" & mul_out_2( 31 downto 0) & "0000000000000000") +
("0000000000000000" & "0000000000000000" & mul_out_3( 31 downto 0));
mul_reg8 <= mul_out(63 downto 56);
mul_reg9 <= mul_out(55 downto 48);
mul_reg10 <= mul_out(47 downto 40);
mul_reg11 <= mul_out(39 downto 32);
mul_reg12 <= mul_out(31 downto 24);
mul_reg13 <= mul_out(23 downto 16);
mul_reg14 <= mul_out(15 downto 8);
mul_reg15 <= mul_out( 7 downto 0);
end process;
)
variable mul_left_hi : std_logic_vector(17 downto 0);
variable mul_left_lo : std_logic_vector(17 downto 0);
variable mul_right_hi : std_logic_vector(17 downto 0);
variable mul_right_lo : std_logic_vector(17 downto 0);
variable mul_out_0 : std_logic_vector(35 downto 0);
variable mul_out_1 : std_logic_vector(35 downto 0);
variable mul_out_2 : std_logic_vector(35 downto 0);
variable mul_out_3 : std_logic_vector(35 downto 0);
variable mul_out : std_logic_vector(63 downto 0);
begin
mul_left_hi := "00" & mul_reg0 & mul_reg1;
mul_left_lo := "00" & mul_reg2 & mul_reg3;
mul_right_hi := "00" & mul_reg4 & mul_reg5;
mul_right_lo := "00" &mul_reg6 & mul_reg7;
mul_out_0 := mul_left_hi * mul_right_hi;
mul_out_1 := mul_left_hi * mul_right_lo;
mul_out_2 := mul_left_lo * mul_right_hi;
mul_out_3 := mul_left_lo * mul_right_lo;
mul_out := (mul_out_0( 31 downto 0) & "0000000000000000" & "0000000000000000") +
("0000000000000000" & mul_out_1( 31 downto 0) & "0000000000000000") +
("0000000000000000" & mul_out_2( 31 downto 0) & "0000000000000000") +
("0000000000000000" & "0000000000000000" & mul_out_3( 31 downto 0));
mul_reg8 <= mul_out(63 downto 56);
mul_reg9 <= mul_out(55 downto 48);
mul_reg10 <= mul_out(47 downto 40);
mul_reg11 <= mul_out(39 downto 32);
mul_reg12 <= mul_out(31 downto 24);
mul_reg13 <= mul_out(23 downto 16);
mul_reg14 <= mul_out(15 downto 8);
mul_reg15 <= mul_out( 7 downto 0);
end process;
 
end rtl;
/SevenSegment.vhd
1,36 → 1,64
--===========================================================================--
--===========================================================================--
-- --
-- SevenSegment.vhd - Synthesizable Multiplex Seven Segment LED Driver --
-- --
--===========================================================================--
--
-- S Y N T H E Z I A B L E Dynamic Address Translation Registers
-- File name : SevenSegment.vhd
--
-- www.OpenCores.Org - December 2002
-- This core adheres to the GNU public license
-- Entity name : SevenSegment
--
-- File name : SevenSegment.vhd
--
-- entity name : SevenSegment
--
-- Purpose : 4 x 8 bit lathes to display 7 segments
-- Purpose : 4 x 8 bit lathes to display 7 segments
-- Multiplexes segment registers across 4 displays.
-- For use on the Digilent Spartan 3 Starter Board
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
-- 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
--
-- SevenSegment.vhd is a multiplexed seven segment LED display driver written in VHDL
--
-- Copyright (C) 2004 - 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 Author Date Description
-- 0.1 John Kent 19 Oct 2004 Initial version
-- 0.2 John Kent 21 Nov 2006 Inverted segment registers
-- so '0' in segment registers
-- switches segment OFF
-- 0.3 John Kent 31 May 2010 Updated Header and GPL.
--
-- Author : John E. Kent
--
--===========================================================================----
--
-- Revision History:
--
-- Date Revision Author
-- 19 Oct 2004 0.1 John Kent
--
-- 21 Nov 2006 0.2 John Kent
-- Inverted segment registers
-- so '0' in segment registers switches segment OFF
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
library unisim;
use unisim.vcomponents.all;
 
entity seven_segment is
port (
47,13 → 75,13
end;
 
architecture rtl of seven_segment is
signal seg_reg0 : std_logic_vector(7 downto 0);
signal seg_reg1 : std_logic_vector(7 downto 0);
signal seg_reg2 : std_logic_vector(7 downto 0);
signal seg_reg3 : std_logic_vector(7 downto 0);
signal seg_reg0 : std_logic_vector(7 downto 0);
signal seg_reg1 : std_logic_vector(7 downto 0);
signal seg_reg2 : std_logic_vector(7 downto 0);
signal seg_reg3 : std_logic_vector(7 downto 0);
 
signal ClockDivider : std_logic_vector(13 downto 0);
signal WhichDigit : std_logic_vector(1 downto 0);
signal ClockDivider : std_logic_vector(13 downto 0);
signal WhichDigit : std_logic_vector(1 downto 0);
 
begin
 
134,13 → 162,13
Digits <= "1110";
Segments <= not( seg_reg0 );
when "01" =>
Digits <= "1101";
Digits <= "1101";
Segments <= not( seg_reg1 );
when "10" =>
Digits <= "1011";
Digits <= "1011";
Segments <= not( seg_reg2 );
when "11" =>
Digits <= "0111";
Digits <= "0111";
Segments <= not( seg_reg3 );
when others =>
null;
/pia_timer.vhd
1,522 → 1,554
-- $Id: pia_timer.vhd,v 1.2 2008-03-14 15:52:46 dilbert57 Exp $
--===========================================================================--
--
-- S Y N T H E Z I A B L E I/O Port C O R E
--
-- www.OpenCores.Org - May 2004
-- This core adheres to the GNU public license
--
-- File name : pia_timer.vhd
--
-- Purpose : Implements 2 x 8 bit parallel I/O ports
-- with 8 bit presetable counter.
-- port a = output connected to presettable counter input
-- port b = input connected to counter output
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
--
-- Author : John E. Kent
--
--===========================================================================----
--
-- Revision History:
--
-- Date: Revision Author
-- 1 May 2004 0.0 John Kent
-- Initial version developed from ioport.vhd
--
-- 22 April 2006 1.0 John Kent
-- Removed I/O ports and hard wired a binary
-- down counter. Port A is the preset output.
-- Port B is the timer count input.
-- CA1 & CB1 are interrupt inputs
-- CA2 is the counter load (active low)
-- CB2 is the counter reset (active high)
-- It may be necessary to offset the counter
-- to compensate for differences in cpu cycle
-- times between FPGA and real 6809 systems.
--
-- 24 May 2006 1.1 John Kent
-- Modified counter to subtract one from preset
-- so FPGA version of the CMC_BUG monitor is
-- compatible with the reference design.
--
--===========================================================================----
--
-- Memory Map
--
-- IO + $00 - Port A Data & Direction register
-- IO + $01 - Port A Control register
-- IO + $02 - Port B Data & Direction Direction Register
-- IO + $03 - Port B Control Register
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity pia_timer is
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector(1 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
irqa : out std_logic;
irqb : out std_logic
);
end;
 
architecture pia_arch of pia_timer is
 
signal pa : std_logic_vector(7 downto 0);
signal porta_ddr : std_logic_vector(7 downto 0);
signal porta_data : std_logic_vector(7 downto 0);
signal porta_ctrl : std_logic_vector(5 downto 0);
signal porta_read : std_logic;
 
signal pb : std_logic_vector(7 downto 0);
signal portb_ddr : std_logic_vector(7 downto 0);
signal portb_data : std_logic_vector(7 downto 0);
signal portb_ctrl : std_logic_vector(5 downto 0);
signal portb_read : std_logic;
signal portb_write : std_logic;
 
signal ca1 : std_logic;
signal ca1_del : std_logic;
signal ca1_rise : std_logic;
signal ca1_fall : std_logic;
signal ca1_edge : std_logic;
signal irqa1 : std_logic;
 
signal ca2 : std_logic;
signal ca2_del : std_logic;
signal ca2_rise : std_logic;
signal ca2_fall : std_logic;
signal ca2_edge : std_logic;
signal irqa2 : std_logic;
signal ca2_out : std_logic;
 
signal cb1 : std_logic;
signal cb1_del : std_logic;
signal cb1_rise : std_logic;
signal cb1_fall : std_logic;
signal cb1_edge : std_logic;
signal irqb1 : std_logic;
 
signal cb2 : std_logic;
signal cb2_del : std_logic;
signal cb2_rise : std_logic;
signal cb2_fall : std_logic;
signal cb2_edge : std_logic;
signal irqb2 : std_logic;
signal cb2_out : std_logic;
 
-- 74193 down counter
signal timer : std_logic_vector(7 downto 0);
 
begin
 
--------------------------------
--
-- read I/O port
--
--------------------------------
 
pia_read : process( addr, cs,
irqa1, irqa2, irqb1, irqb2,
porta_ddr, portb_ddr,
porta_data, portb_data,
porta_ctrl, portb_ctrl,
pa, pb )
variable count : integer;
begin
case addr is
when "00" =>
for count in 0 to 7 loop
if porta_ctrl(2) = '0' then
data_out(count) <= porta_ddr(count);
porta_read <= '0';
else
if porta_ddr(count) = '1' then
data_out(count) <= porta_data(count);
else
data_out(count) <= pa(count);
end if;
porta_read <= cs;
end if;
end loop;
portb_read <= '0';
 
when "01" =>
data_out <= irqa1 & irqa2 & porta_ctrl;
porta_read <= '0';
portb_read <= '0';
 
when "10" =>
for count in 0 to 7 loop
if portb_ctrl(2) = '0' then
data_out(count) <= portb_ddr(count);
portb_read <= '0';
else
if portb_ddr(count) = '1' then
data_out(count) <= portb_data(count);
else
data_out(count) <= pb(count);
end if;
portb_read <= cs;
end if;
end loop;
porta_read <= '0';
 
when "11" =>
data_out <= irqb1 & irqb2 & portb_ctrl;
porta_read <= '0';
portb_read <= '0';
 
when others =>
data_out <= "00000000";
porta_read <= '0';
portb_read <= '0';
 
end case;
end process;
 
---------------------------------
--
-- Write I/O ports
--
---------------------------------
 
pia_write : process( clk, rst, addr, cs, rw, data_in,
porta_ctrl, portb_ctrl,
porta_data, portb_data,
porta_ctrl, portb_ctrl,
porta_ddr, portb_ddr )
begin
if rst = '1' then
porta_ddr <= "00000000";
porta_data <= "00000000";
porta_ctrl <= "000000";
portb_ddr <= "00000000";
portb_data <= "00000000";
portb_ctrl <= "000000";
portb_write <= '0';
elsif clk'event and clk = '1' then
if cs = '1' and rw = '0' then
case addr is
when "00" =>
if porta_ctrl(2) = '0' then
porta_ddr <= data_in;
porta_data <= porta_data;
else
porta_ddr <= porta_ddr;
porta_data <= data_in;
end if;
porta_ctrl <= porta_ctrl;
portb_ddr <= portb_ddr;
portb_data <= portb_data;
portb_ctrl <= portb_ctrl;
portb_write <= '0';
when "01" =>
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= data_in(5 downto 0);
portb_ddr <= portb_ddr;
portb_data <= portb_data;
portb_ctrl <= portb_ctrl;
portb_write <= '0';
when "10" =>
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= porta_ctrl;
if portb_ctrl(2) = '0' then
portb_ddr <= data_in;
portb_data <= portb_data;
portb_write <= '0';
else
portb_ddr <= portb_ddr;
portb_data <= data_in;
portb_write <= '1';
end if;
portb_ctrl <= portb_ctrl;
when "11" =>
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= porta_ctrl;
portb_ddr <= portb_ddr;
portb_data <= portb_data;
portb_ctrl <= data_in(5 downto 0);
portb_write <= '0';
when others =>
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= porta_ctrl;
portb_ddr <= portb_ddr;
portb_data <= portb_data;
portb_ctrl <= portb_ctrl;
portb_write <= '0';
end case;
else
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= porta_ctrl;
portb_data <= portb_data;
portb_ddr <= portb_ddr;
portb_ctrl <= portb_ctrl;
portb_write <= '0';
end if;
end if;
end process;
 
---------------------------------
--
-- CA1 Edge detect
--
---------------------------------
ca1_input : process( clk, rst, ca1, ca1_del,
ca1_rise, ca1_fall, ca1_edge,
irqa1, porta_ctrl, porta_read )
begin
if rst = '1' then
ca1_del <= '0';
ca1_rise <= '0';
ca1_fall <= '0';
ca1_edge <= '0';
irqa1 <= '0';
elsif clk'event and clk = '0' then
ca1_del <= ca1;
ca1_rise <= (not ca1_del) and ca1;
ca1_fall <= ca1_del and (not ca1);
if ca1_edge = '1' then
irqa1 <= '1';
elsif porta_read = '1' then
irqa1 <= '0';
else
irqa1 <= irqa1;
end if;
end if;
 
if porta_ctrl(1) = '0' then
ca1_edge <= ca1_fall;
else
ca1_edge <= ca1_rise;
end if;
end process;
 
---------------------------------
--
-- CA2 Edge detect
--
---------------------------------
ca2_input : process( clk, rst, ca2, ca2_del,
ca2_rise, ca2_fall, ca2_edge,
irqa2, porta_ctrl, porta_read )
begin
if rst = '1' then
ca2_del <= '0';
ca2_rise <= '0';
ca2_fall <= '0';
ca2_edge <= '0';
irqa2 <= '0';
elsif clk'event and clk = '0' then
ca2_del <= ca2;
ca2_rise <= (not ca2_del) and ca2;
ca2_fall <= ca2_del and (not ca2);
if porta_ctrl(5) = '0' and ca2_edge = '1' then
irqa2 <= '1';
elsif porta_read = '1' then
irqa2 <= '0';
else
irqa2 <= irqa2;
end if;
end if;
 
if porta_ctrl(4) = '0' then
ca2_edge <= ca2_fall;
else
ca2_edge <= ca2_rise;
end if;
end process;
 
---------------------------------
--
-- CA2 output control
--
---------------------------------
ca2_output : process( clk, rst, porta_ctrl, porta_read, ca1_edge, ca2_out )
begin
if rst='1' then
ca2_out <= '0';
elsif clk'event and clk='0' then
case porta_ctrl(5 downto 3) is
when "100" => -- read PA clears, CA1 edge sets
if porta_read = '1' then
ca2_out <= '0';
elsif ca1_edge = '1' then
ca2_out <= '1';
else
ca2_out <= ca2_out;
end if;
when "101" => -- read PA clears, E sets
ca2_out <= not porta_read;
when "110" => -- set low
ca2_out <= '0';
when "111" => -- set high
ca2_out <= '1';
when others => -- no change
ca2_out <= ca2_out;
end case;
end if;
end process;
 
 
---------------------------------
--
-- CB1 Edge detect
--
---------------------------------
cb1_input : process( clk, rst, cb1, cb1_del,
cb1_rise, cb1_fall, cb1_edge,
irqb1, portb_ctrl, portb_read )
begin
if rst = '1' then
cb1_del <= '0';
cb1_rise <= '0';
cb1_fall <= '0';
cb1_edge <= '0';
irqb1 <= '0';
elsif clk'event and clk = '0' then
cb1_del <= cb1;
cb1_rise <= (not cb1_del) and cb1;
cb1_fall <= cb1_del and (not cb1);
if cb1_edge = '1' then
irqb1 <= '1';
elsif portb_read = '1' then
irqb1 <= '0';
else
irqb1 <= irqb1;
end if;
end if;
if portb_ctrl(1) = '0' then
cb1_edge <= cb1_fall;
else
cb1_edge <= cb1_rise;
end if;
end process;
 
---------------------------------
--
-- CB2 Edge detect
--
---------------------------------
cb2_input : process( clk, rst, cb2, cb2_del,
cb2_rise, cb2_fall, cb2_edge,
irqb2, portb_ctrl, portb_read )
begin
if rst = '1' then
cb2_del <= '0';
cb2_rise <= '0';
cb2_fall <= '0';
cb2_edge <= '0';
irqb2 <= '0';
elsif clk'event and clk = '0' then
cb2_del <= cb2;
cb2_rise <= (not cb2_del) and cb2;
cb2_fall <= cb2_del and (not cb2);
if portb_ctrl(5) = '0' and cb2_edge = '1' then
irqb2 <= '1';
elsif portb_read = '1' then
irqb2 <= '0';
else
irqb2 <= irqb2;
end if;
end if;
if portb_ctrl(4) = '0' then
cb2_edge <= cb2_fall;
else
cb2_edge <= cb2_rise;
end if;
 
end process;
 
---------------------------------
--
-- CB2 output control
--
---------------------------------
cb2_output : process( clk, rst, portb_ctrl, portb_write, cb1_edge, cb2_out )
begin
if rst='1' then
cb2_out <= '0';
elsif clk'event and clk='0' then
case portb_ctrl(5 downto 3) is
when "100" => -- write PB clears, CA1 edge sets
if portb_write = '1' then
cb2_out <= '0';
elsif cb1_edge = '1' then
cb2_out <= '1';
else
cb2_out <= cb2_out;
end if;
when "101" => -- write PB clears, E sets
cb2_out <= not portb_write;
when "110" => -- set low
cb2_out <= '0';
when "111" => -- set high
cb2_out <= '1';
when others => -- no change
cb2_out <= cb2_out;
end case;
end if;
end process;
 
---------------------------------
--
-- IRQ control
--
---------------------------------
pia_irq : process( irqa1, irqa2, irqb1, irqb2, porta_ctrl, portb_ctrl )
begin
irqa <= (irqa1 and porta_ctrl(0)) or (irqa2 and porta_ctrl(3));
irqb <= (irqb1 and portb_ctrl(0)) or (irqb2 and portb_ctrl(3));
end process;
 
---------------------------------
--
-- 2 x 74193 binary down counter
--
---------------------------------
--
-- On the reference 6809 board,
-- RTI takes one more clock cycle than System09
-- So subtract 1 from the porta_data preset value.
-- 11th July 2006 John Kent
-- RTI in CPU09 has been extended by one bus cycle
-- so remove the subtract by one offset on porta_data
--
pia_counter : process( clk, timer, porta_data, ca2_out, cb2_out)
begin
if cb2_out = '1' then
timer <= "00000000";
elsif ca2_out = '0' then
-- timer <= porta_data - "00000001";
timer <= porta_data;
elsif clk'event and clk='1' then
timer <= timer - "00000001";
end if;
pa <= "00000000";
pb <= timer;
ca1 <= timer(7);
cb1 <= timer(7);
ca2 <= '0';
cb2 <= '0';
end process;
end pia_arch;
--===========================================================================--
-- --
-- pia_timer.vhd - Synthesizable Parallel Interface Adapter with Timer --
-- --
--===========================================================================--
--
-- File name : pia_timer.vhd
--
-- Entity name : pia_timer
--
-- Purpose : Implements 2 x 8 bit parallel I/O ports
-- with 8 bit presetable counter.
-- Port A Data = output connected to presettable counter input
-- Port B Data = input connected to counter output
-- Used with Digilent Spartan 3E starter board
-- to implement a single step trace function.
--
-- 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
--
-- Description : Register Memory Map
--
-- Base + $00 - Port A Data & Direction register
-- Base + $01 - Port A Control register
-- Base + $02 - Port B Data & Direction Direction Register
-- Base + $03 - Port B Control Register
--
-- Copyright (C) 2004 - 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 Author Date Description
-- 0.0 John Kent 1st May 2004 Initial version developed from ioport.vhd
--
-- 1.0 John Kent 22nd April 2006 Removed I/O ports and hard wired a binary
-- down counter. Port A is the preset output.
-- Port B is the timer count input.
-- CA1 & CB1 are interrupt inputs
-- CA2 is the counter load (active low)
-- CB2 is the counter reset (active high)
-- It may be necessary to offset the counter
-- to compensate for differences in cpu cycle
-- times between FPGA and real 6809 systems.
--
-- 1.1 John Kent 24th May 2006 Modified counter to subtract one from preset
-- so FPGA version of the CMC_BUG monitor is
-- compatible with the reference design.
--
-- 1.2 John Kent 30th May 2010 Revised header and added updated GPL
--
--===========================================================================----
--
-- Memory Map
--
-- IO + $00 - Port A Data & Direction register
-- IO + $01 - Port A Control register
-- IO + $02 - Port B Data & Direction Direction Register
-- IO + $03 - Port B Control Register
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
library unisim;
use unisim.vcomponents.all;
 
entity pia_timer is
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector(1 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
irqa : out std_logic;
irqb : out std_logic
);
end;
 
architecture pia_arch of pia_timer is
 
signal pa : std_logic_vector(7 downto 0);
signal porta_ddr : std_logic_vector(7 downto 0);
signal porta_data : std_logic_vector(7 downto 0);
signal porta_ctrl : std_logic_vector(5 downto 0);
signal porta_read : std_logic;
 
signal pb : std_logic_vector(7 downto 0);
signal portb_ddr : std_logic_vector(7 downto 0);
signal portb_data : std_logic_vector(7 downto 0);
signal portb_ctrl : std_logic_vector(5 downto 0);
signal portb_read : std_logic;
signal portb_write : std_logic;
 
signal ca1 : std_logic;
signal ca1_del : std_logic;
signal ca1_rise : std_logic;
signal ca1_fall : std_logic;
signal ca1_edge : std_logic;
signal irqa1 : std_logic;
 
signal ca2 : std_logic;
signal ca2_del : std_logic;
signal ca2_rise : std_logic;
signal ca2_fall : std_logic;
signal ca2_edge : std_logic;
signal irqa2 : std_logic;
signal ca2_out : std_logic;
 
signal cb1 : std_logic;
signal cb1_del : std_logic;
signal cb1_rise : std_logic;
signal cb1_fall : std_logic;
signal cb1_edge : std_logic;
signal irqb1 : std_logic;
 
signal cb2 : std_logic;
signal cb2_del : std_logic;
signal cb2_rise : std_logic;
signal cb2_fall : std_logic;
signal cb2_edge : std_logic;
signal irqb2 : std_logic;
signal cb2_out : std_logic;
 
-- 74193 down counter
signal timer : std_logic_vector(7 downto 0);
 
begin
 
--------------------------------
--
-- read I/O port
--
--------------------------------
 
pia_read : process( addr, cs,
irqa1, irqa2, irqb1, irqb2,
porta_ddr, portb_ddr,
porta_data, portb_data,
porta_ctrl, portb_ctrl,
pa, pb )
variable count : integer;
begin
case addr is
when "00" =>
for count in 0 to 7 loop
if porta_ctrl(2) = '0' then
data_out(count) <= porta_ddr(count);
porta_read <= '0';
else
if porta_ddr(count) = '1' then
data_out(count) <= porta_data(count);
else
data_out(count) <= pa(count);
end if;
porta_read <= cs;
end if;
end loop;
portb_read <= '0';
 
when "01" =>
data_out <= irqa1 & irqa2 & porta_ctrl;
porta_read <= '0';
portb_read <= '0';
 
when "10" =>
for count in 0 to 7 loop
if portb_ctrl(2) = '0' then
data_out(count) <= portb_ddr(count);
portb_read <= '0';
else
if portb_ddr(count) = '1' then
data_out(count) <= portb_data(count);
else
data_out(count) <= pb(count);
end if;
portb_read <= cs;
end if;
end loop;
porta_read <= '0';
 
when "11" =>
data_out <= irqb1 & irqb2 & portb_ctrl;
porta_read <= '0';
portb_read <= '0';
 
when others =>
data_out <= "00000000";
porta_read <= '0';
portb_read <= '0';
 
end case;
end process;
 
---------------------------------
--
-- Write I/O ports
--
---------------------------------
 
pia_write : process( clk, rst, addr, cs, rw, data_in,
porta_ctrl, portb_ctrl,
porta_data, portb_data,
porta_ctrl, portb_ctrl,
porta_ddr, portb_ddr )
begin
if rst = '1' then
porta_ddr <= "00000000";
porta_data <= "00000000";
porta_ctrl <= "000000";
portb_ddr <= "00000000";
portb_data <= "00000000";
portb_ctrl <= "000000";
portb_write <= '0';
elsif clk'event and clk = '1' then
if cs = '1' and rw = '0' then
case addr is
when "00" =>
if porta_ctrl(2) = '0' then
porta_ddr <= data_in;
porta_data <= porta_data;
else
porta_ddr <= porta_ddr;
porta_data <= data_in;
end if;
porta_ctrl <= porta_ctrl;
portb_ddr <= portb_ddr;
portb_data <= portb_data;
portb_ctrl <= portb_ctrl;
portb_write <= '0';
when "01" =>
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= data_in(5 downto 0);
portb_ddr <= portb_ddr;
portb_data <= portb_data;
portb_ctrl <= portb_ctrl;
portb_write <= '0';
when "10" =>
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= porta_ctrl;
if portb_ctrl(2) = '0' then
portb_ddr <= data_in;
portb_data <= portb_data;
portb_write <= '0';
else
portb_ddr <= portb_ddr;
portb_data <= data_in;
portb_write <= '1';
end if;
portb_ctrl <= portb_ctrl;
when "11" =>
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= porta_ctrl;
portb_ddr <= portb_ddr;
portb_data <= portb_data;
portb_ctrl <= data_in(5 downto 0);
portb_write <= '0';
when others =>
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= porta_ctrl;
portb_ddr <= portb_ddr;
portb_data <= portb_data;
portb_ctrl <= portb_ctrl;
portb_write <= '0';
end case;
else
porta_ddr <= porta_ddr;
porta_data <= porta_data;
porta_ctrl <= porta_ctrl;
portb_data <= portb_data;
portb_ddr <= portb_ddr;
portb_ctrl <= portb_ctrl;
portb_write <= '0';
end if;
end if;
end process;
 
---------------------------------
--
-- CA1 Edge detect
--
---------------------------------
ca1_input : process( clk, rst, ca1, ca1_del,
ca1_rise, ca1_fall, ca1_edge,
irqa1, porta_ctrl, porta_read )
begin
if rst = '1' then
ca1_del <= '0';
ca1_rise <= '0';
ca1_fall <= '0';
ca1_edge <= '0';
irqa1 <= '0';
elsif clk'event and clk = '0' then
ca1_del <= ca1;
ca1_rise <= (not ca1_del) and ca1;
ca1_fall <= ca1_del and (not ca1);
if ca1_edge = '1' then
irqa1 <= '1';
elsif porta_read = '1' then
irqa1 <= '0';
else
irqa1 <= irqa1;
end if;
end if;
 
if porta_ctrl(1) = '0' then
ca1_edge <= ca1_fall;
else
ca1_edge <= ca1_rise;
end if;
end process;
 
---------------------------------
--
-- CA2 Edge detect
--
---------------------------------
ca2_input : process( clk, rst, ca2, ca2_del,
ca2_rise, ca2_fall, ca2_edge,
irqa2, porta_ctrl, porta_read )
begin
if rst = '1' then
ca2_del <= '0';
ca2_rise <= '0';
ca2_fall <= '0';
ca2_edge <= '0';
irqa2 <= '0';
elsif clk'event and clk = '0' then
ca2_del <= ca2;
ca2_rise <= (not ca2_del) and ca2;
ca2_fall <= ca2_del and (not ca2);
if porta_ctrl(5) = '0' and ca2_edge = '1' then
irqa2 <= '1';
elsif porta_read = '1' then
irqa2 <= '0';
else
irqa2 <= irqa2;
end if;
end if;
 
if porta_ctrl(4) = '0' then
ca2_edge <= ca2_fall;
else
ca2_edge <= ca2_rise;
end if;
end process;
 
---------------------------------
--
-- CA2 output control
--
---------------------------------
ca2_output : process( clk, rst, porta_ctrl, porta_read, ca1_edge, ca2_out )
begin
if rst='1' then
ca2_out <= '0';
elsif clk'event and clk='0' then
case porta_ctrl(5 downto 3) is
when "100" => -- read PA clears, CA1 edge sets
if porta_read = '1' then
ca2_out <= '0';
elsif ca1_edge = '1' then
ca2_out <= '1';
else
ca2_out <= ca2_out;
end if;
when "101" => -- read PA clears, E sets
ca2_out <= not porta_read;
when "110" => -- set low
ca2_out <= '0';
when "111" => -- set high
ca2_out <= '1';
when others => -- no change
ca2_out <= ca2_out;
end case;
end if;
end process;
 
 
---------------------------------
--
-- CB1 Edge detect
--
---------------------------------
cb1_input : process( clk, rst, cb1, cb1_del,
cb1_rise, cb1_fall, cb1_edge,
irqb1, portb_ctrl, portb_read )
begin
if rst = '1' then
cb1_del <= '0';
cb1_rise <= '0';
cb1_fall <= '0';
cb1_edge <= '0';
irqb1 <= '0';
elsif clk'event and clk = '0' then
cb1_del <= cb1;
cb1_rise <= (not cb1_del) and cb1;
cb1_fall <= cb1_del and (not cb1);
if cb1_edge = '1' then
irqb1 <= '1';
elsif portb_read = '1' then
irqb1 <= '0';
else
irqb1 <= irqb1;
end if;
end if;
if portb_ctrl(1) = '0' then
cb1_edge <= cb1_fall;
else
cb1_edge <= cb1_rise;
end if;
end process;
 
---------------------------------
--
-- CB2 Edge detect
--
---------------------------------
cb2_input : process( clk, rst, cb2, cb2_del,
cb2_rise, cb2_fall, cb2_edge,
irqb2, portb_ctrl, portb_read )
begin
if rst = '1' then
cb2_del <= '0';
cb2_rise <= '0';
cb2_fall <= '0';
cb2_edge <= '0';
irqb2 <= '0';
elsif clk'event and clk = '0' then
cb2_del <= cb2;
cb2_rise <= (not cb2_del) and cb2;
cb2_fall <= cb2_del and (not cb2);
if portb_ctrl(5) = '0' and cb2_edge = '1' then
irqb2 <= '1';
elsif portb_read = '1' then
irqb2 <= '0';
else
irqb2 <= irqb2;
end if;
end if;
if portb_ctrl(4) = '0' then
cb2_edge <= cb2_fall;
else
cb2_edge <= cb2_rise;
end if;
 
end process;
 
---------------------------------
--
-- CB2 output control
--
---------------------------------
cb2_output : process( clk, rst, portb_ctrl, portb_write, cb1_edge, cb2_out )
begin
if rst='1' then
cb2_out <= '0';
elsif clk'event and clk='0' then
case portb_ctrl(5 downto 3) is
when "100" => -- write PB clears, CA1 edge sets
if portb_write = '1' then
cb2_out <= '0';
elsif cb1_edge = '1' then
cb2_out <= '1';
else
cb2_out <= cb2_out;
end if;
when "101" => -- write PB clears, E sets
cb2_out <= not portb_write;
when "110" => -- set low
cb2_out <= '0';
when "111" => -- set high
cb2_out <= '1';
when others => -- no change
cb2_out <= cb2_out;
end case;
end if;
end process;
 
---------------------------------
--
-- IRQ control
--
---------------------------------
pia_irq : process( irqa1, irqa2, irqb1, irqb2, porta_ctrl, portb_ctrl )
begin
irqa <= (irqa1 and porta_ctrl(0)) or (irqa2 and porta_ctrl(3));
irqb <= (irqb1 and portb_ctrl(0)) or (irqb2 and portb_ctrl(3));
end process;
 
---------------------------------
--
-- 2 x 74193 binary down counter
--
---------------------------------
--
-- On the reference 6809 board,
-- RTI takes one more clock cycle than System09
-- So subtract 1 from the porta_data preset value.
-- 11th July 2006 John Kent
-- RTI in CPU09 has been extended by one bus cycle
-- so remove the subtract by one offset on porta_data
--
pia_counter : process( clk, timer, porta_data, ca2_out, cb2_out)
begin
if cb2_out = '1' then
timer <= "00000000";
elsif ca2_out = '0' then
-- timer <= porta_data - "00000001";
timer <= porta_data;
elsif clk'event and clk='1' then
timer <= timer - "00000001";
end if;
pa <= "00000000";
pb <= timer;
ca1 <= timer(7);
cb1 <= timer(7);
ca2 <= '0';
cb2 <= '0';
end process;
end pia_arch;
/quadcpu09.vhd
1,61 → 1,90
--===========================================================================----
--===========================================================================--
-- --
-- Synthesizable Quad Core 6809 instruction compatible CPU Module --
-- --
--===========================================================================--
--
-- S Y N T H E Z I A B L E unicpu09.vhd - Quad core 6809 processor
-- File name : quadcpu09.vhd
--
-- Entity name : quadcpu09
--
--===========================================================================----
-- Purpose : Top level file for quad Core 6809 compatible system on a chip
-- Designed for Xilinx XC3S1000 Spartan 3 FPGA.
-- Intended for Digilent Xilinx Spartan 3 Starter FPGA board,
-- or XESS XSA-3S1000 FPGA board.
--
-- This core adheres to the GNU public license
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
-- ieee.std_logic_arith
-- ieee.numeric_std
-- unisim.vcomponents
-- work.bit_funcs
--
-- Status: : *** Still under development ***
--
-- File name : quadcpu09.vhd
-- Uses : unicpu09 (unicpu09.vhd) CPU09 core module
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- quadcpu09.vhd is a top level file for a quad CPU09 core written in VHDL.
--
-- 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 Author Date Description
-- 0.1 John Kent 20th March 2003 Initial version
-- 0.2 John Kent 30th May 2010 Updated Header and GPL
--
-- Purpose : Top level file for quad Core 6809 compatible system on a chip
-- Designed with Xilinx XC3S1000 Spartan 3 FPGA.
-- Implemented With Digilent Xilinx Starter FPGA board,
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
-- ieee.std_logic_arith
-- ieee.numeric_std
--
-- Uses :
-- unicpu09 (unicpu09.vhd) 6809 CPU core module
--
-- Author : John E. Kent
-- dilbert57@opencores.org
--
--===========================================================================----
--
-- Revision History:
--
--===========================================================================--
-- Version 0.1 - 20 March 2003
--
--===========================================================================--
 
 
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
 
library unisim;
use unisim.vcomponents.all;
 
library work;
use work.bit_funcs.all;
 
entity quadcpu09 is
entity quadcpu09 is
port (
clk : in std_logic;
rst : in std_logic;
vma : out std_logic;
addr : out std_logic_vector(19 downto 0);
rw : out std_logic;
vma : out std_logic;
address : out std_logic_vector(19 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
halt : in std_logic;
hold : in std_logic;
irq : in std_logic;
nmi : in std_logic;
firq : in std_logic
firq : in std_logic;
halt : in std_logic;
hold : in std_logic
);
end entity;
 
62,18 → 91,18
-------------------------------------------------------------------------------
-- Architecture for System09
-------------------------------------------------------------------------------
architecture RTL of quadcpu09 is
 
constant CPU_MAX : integer := 4;
constant ADDR_WIDTH : integer := 20;
constant DATA_WIDTH : integer := 8;
 
type addr_type is std_logic_vector(ADDR_WIDTH-1 downto 0);
type data_type is std_logic_vector(DATA_WIDTH-1 downto 0);
type cpu_type is std_logic_vector( CPU_MAX-1 downto 0);
architecture RTL of quadcpu09 is
 
constant CPU_MAX : integer := 4;
constant ADDR_WIDTH : integer := 20;
constant DATA_WIDTH : integer := 8;
 
type addr_type is std_logic_vector(ADDR_WIDTH-1 downto 0);
type data_type is std_logic_vector(DATA_WIDTH-1 downto 0);
type cpu_type is std_logic_vector( CPU_MAX-1 downto 0);
type addr_array is array(0 to (CPU_MAX-1)) of addr_type;
type data_array is array(0 to (CPU_MAX-1)) of data_type;
 
 
-- CPU Interface signals
signal cpu_rw : cpu_type;
signal cpu_vma : cpu_type;
80,245 → 109,242
signal cpu_addr : addr_array;
signal cpu_id : data_array;
signal cpu_halt : cpu_type;
signal cpu_hold : cpu_type;
signal cpu_irq : cpu_type;
signal cpu_nmi : cpu_type;
signal cpu_hold : cpu_type;
signal cpu_irq : cpu_type;
signal cpu_nmi : cpu_type;
signal cpu_firq : cpu_type;
signal mem_rw : std_logic;
signal mem_vma : std_logic;
signal mem_addr : addr_type;
signal mem_rw : std_logic;
signal mem_vma : std_logic;
signal mem_addr : addr_type;
signal mem_dati : data_type;
signal mem_dato : data_array;
 
--
-- priority encoder
--
signal pri_rot : std_logic; -- rotate the priority
signal pri_cnt : std_logic_vector( log2(CPU_MAX)-1 downto 0); -- priority rotation counter
signal pri_mux : std_logic_vector( (CPU_MAX-1) downto 0); -- rotated bus request
signal pri_enc : std_logic_vector( log2(CPU_MAX)-1 downto 0); -- encoded rotated bus request
signal pri_req : std_logic; -- encoded bus request valid
 
 
component my_unicpu09
generic(
);
 
 
--
-- priority encoder
--
signal pri_rot : std_logic; -- rotate the priority
signal pri_cnt : std_logic_vector( log2(CPU_MAX)-1 downto 0); -- priority rotation counter
signal pri_mux : std_logic_vector( (CPU_MAX-1) downto 0); -- rotated bus request
signal pri_enc : std_logic_vector( log2(CPU_MAX)-1 downto 0); -- encoded rotated bus request
signal pri_req : std_logic; -- encoded bus request valid
 
 
component my_unicpu09
port(
clk : in std_logic;
rst : in std_logic;
rst : in std_logic;
--
-- cpu side signals
--
-- cpu side signals
--
rw : out std_logic;
vma : out std_logic;
addr : out addr_type;
cpu_id : in data_type;
rw : out std_logic;
cpu_id : in data_type;
--
-- memory side signals
--
-- memory side signals
--
mem_rw : in std_logic;
mem_vma : in std_logic;
mem_addr : in addr_type;
mem_dati : in data_type;
mem_dato : out data_type;
mem_dato : out data_type;
--
-- controls
--
-- controls
--
halt : in std_logic;
hold : in std_logic;
irq : in std_logic;
nmi : in std_logic;
firq : in std_logic
);
);
end component;
 
 
 
begin
-----------------------------------------------------------------------------
-- Instantiation of internal components
-----------------------------------------------------------------------------
 
my_unicpu09_0 : unicpu09
my_unicpu09_0 : unicpu09
port map (
clk => clk,
rst => rst,
rw => cpu_rw(0),
vma => cpu_vma(0),
addr => cpu_addr(0),
id => "00000000",
--
-- memory side signals
rw => cpu_rw(0),
id => "00000000",
--
-- memory side signals
--
mem_rw => mem_rw,
mem_vma => mem_vma,
mem_addr => mem_addr,
mem_dati => mem_dati,
mem_dato => mem_dato(0),
--
-- cpu controls
--
halt => cpu_halt(0),
hold => cpu_hold(0),
mem_vma => mem_vma,
mem_addr => mem_addr,
mem_rw => mem_rw,
mem_dati => mem_dati,
mem_dato => mem_dato(0),
--
-- cpu controls
--
irq => cpu_irq(0),
nmi => cpu_nmi(0),
firq => cpu_firq(0)
firq => cpu_firq(0),
halt => cpu_halt(0),
hold => cpu_hold(0)
);
 
my_unicpu09_1 : unicpu09
 
my_unicpu09_1 : unicpu09
port map (
clk => clk,
rst => rst,
rw => cpu_rw(1),
vma => cpu_vma(1),
addr => cpu_addr(1),
id => "00010000",
--
-- memory side signals
rw => cpu_rw(1),
id => "00010000",
--
-- memory side signals
--
mem_rw => mem_rw,
mem_vma => mem_vma,
mem_addr => mem_addr,
mem_dati => mem_dati,
mem_dato => mem_dato(1),
--
-- cpu controls
--
halt => cpu_halt(1),
hold => cpu_hold(1),
mem_vma => mem_vma,
mem_addr => mem_addr,
mem_rw => mem_rw,
mem_dati => mem_dati,
mem_dato => mem_dato(1),
--
-- cpu controls
--
irq => cpu_irq(1),
nmi => cpu_nmi(1),
firq => cpu_firq(1)
firq => cpu_firq(1),
halt => cpu_halt(1),
hold => cpu_hold(1)
);
 
my_unicpu09_2 : unicpu09
 
my_unicpu09_2 : unicpu09
port map (
clk => clk,
rst => rst,
rw => cpu_rw(2),
vma => cpu_vma(2),
addr => cpu_addr(2),
id => "00100000"
--
-- memory side signals
rw => cpu_rw(2),
id => "00100000"
--
-- memory side signals
--
mem_rw => mem_rw,
mem_vma => mem_vma,
mem_addr => mem_addr,
mem_dati => mem_dati,
mem_dato => mem_dato(2),
--
-- cpu controls
--
halt => cpu_halt(2),
hold => cpu_hold(2),
mem_vma => mem_vma,
mem_addr => mem_addr,
mem_rw => mem_rw,
mem_dati => mem_dati,
mem_dato => mem_dato(2),
--
-- cpu controls
--
irq => cpu_irq(2),
nmi => cpu_nmi(2),
firq => cpu_firq(2)
firq => cpu_firq(2),
halt => cpu_halt(2),
hold => cpu_hold(2)
);
 
my_unicpu09_3 : unicpu09
 
my_unicpu09_3 : unicpu09
port map (
clk => clk,
rst => rst,
rw => cpu_rw(3),
vma => cpu_vma(3),
addr => cpu_addr(3),
id => "00110000",
--
-- memory side signals
rw => cpu_rw(3),
id => "00110000",
--
-- memory side signals
--
mem_rw => mem_rw,
mem_vma => mem_vma,
mem_addr => mem_addr,
mem_dati => mem_dati,
mem_dato => mem_dato(3),
--
-- cpu controls
--
halt => cpu_halt(3),
hold => cpu_hold(3),
mem_vma => mem_vma,
mem_addr => mem_addr,
mem_rw => mem_rw,
mem_dati => mem_dati,
mem_dato => mem_dato(3),
--
-- cpu controls
--
irq => cpu_irq(3),
nmi => cpu_nmi(3),
firq => cpu_firq(3)
firq => cpu_firq(3),
halt => cpu_halt(3),
hold => cpu_hold(3)
);
 
--
-- Rotating priority
--
my_pri_rotate : process( rst, clk )
variable cpu_count : integer := 0;
begin
if rst = '1' then
pri_cnt <= (others=>0);
if falling_edge(clk) then
if pri_rot = '1' then
pri_cnt <= pri_cnt + 1;
end if;
end if;
end process;
 
--
-- Rotate VMA request
--
my_pri_mux : process( pri_cnt )
begin
case pri_cnt is
when "00" =>
pri_mux <= cpu_vma(3 downto 0);
when "01" =>
pri_mux <= cpu_vma(2 downto 0) & cpu_vma(3);
when "10" =>
pri_mux <= cpu_vma(1 downto 0) & cpu_vma(3 downto 2);
when "11" =>
pri_mux <= cpu_vma(0) & cpu_vma(3 downto 1);
when other =>
null;
end case;
end process;
 
--
-- Priority Encode Rotated VMA Request
--
my_pri_encoder : process( pri_mux )
variable enc_bits : integer := 0;
variable cpu_bits : integer := 0;
begin
for cpu_bits in 0 to (CPU_MAX-1) loop
pri_req := pri_req or pri_mux(cpu_bits);
end loop;
 
for enc_bits in 0 to log2(CPU_MAX)-1 loop
pri_enc(enc_bits) <= '0';
for cpu_bits in 0 to (CPU_MAX-1) loop
if (cpu_bits and pow2(enc_bits)) /= 0 then
pri_enc(enc_bits) <= pri_enc(enc_bits) or pri_mux(cpu_bits);
end if;
end loop;
end loop;
end process;
 
--
-- Grant highest priority requesting processor access to the bus
--
my_bus_grant : process( rst, clk )
begin
 
end process;
 
--
-- Hold processor until bus cycle acknowledged
--
my_hold_machine : process( rst, clk )
variable cpu_bits : integer := 0;
begin
for cpu_bits in 0 to (CPU_MAX-1) loop
if rst = '1' then
cpu_hold( cpu_bits ) <= '0';
elsif rising_edge( clk ) then
cpu_hold( cpu_bits ) <= cpu_vma( cpu_bits ) and (not cpu_ack( cpu_bits ));
end if;
end loop;
end process;
 
end architecture;
 
--
-- Rotating priority
--
my_pri_rotate : process( rst, clk )
variable cpu_count : integer := 0;
begin
if rst = '1' then
pri_cnt <= (others=>0);
if falling_edge(clk) then
if pri_rot = '1' then
pri_cnt <= pri_cnt + 1;
end if;
end if;
end process;
 
--
-- Rotate VMA request
--
my_pri_mux : process( pri_cnt )
begin
case pri_cnt is
when "00" =>
pri_mux <= cpu_vma(3 downto 0);
when "01" =>
pri_mux <= cpu_vma(2 downto 0) & cpu_vma(3);
when "10" =>
pri_mux <= cpu_vma(1 downto 0) & cpu_vma(3 downto 2);
when "11" =>
pri_mux <= cpu_vma(0) & cpu_vma(3 downto 1);
when other =>
null;
end case;
end process;
 
--
-- Priority Encode Rotated VMA Request
--
my_pri_encoder : process( pri_mux )
variable enc_bits : integer := 0;
variable cpu_bits : integer := 0;
begin
for cpu_bits in 0 to (CPU_MAX-1) loop
pri_req := pri_req or pri_mux(cpu_bits);
end loop;
 
for enc_bits in 0 to log2(CPU_MAX)-1 loop
pri_enc(enc_bits) <= '0';
for cpu_bits in 0 to (CPU_MAX-1) loop
if (cpu_bits and pow2(enc_bits)) /= 0 then
pri_enc(enc_bits) <= pri_enc(enc_bits) or pri_mux(cpu_bits);
end if;
end loop;
end loop;
end process;
 
--
-- Grant highest priority requesting processor access to the bus
--
my_bus_grant : process( rst, clk )
begin
 
end process;
 
--
-- Hold processor until bus cycle acknowledged
--
my_hold_machine : process( rst, clk )
variable cpu_bits : integer := 0;
begin
for cpu_bits in 0 to (CPU_MAX-1) loop
if rst = '1' then
cpu_hold( cpu_bits ) <= '0';
elsif rising_edge( clk ) then
cpu_hold( cpu_bits ) <= cpu_vma( cpu_bits ) and (not cpu_ack( cpu_bits ));
end if;
end loop;
end process;
 
end architecture;
/ioport.vhd
1,37 → 1,54
--===========================================================================----
--===========================================================================--
-- --
-- ioport.vhd - Synthesizable Dual Bidirectionsal I/O Port --
-- --
--===========================================================================--
--
-- S Y N T H E Z I A B L E ioport - 2 x 8 bit parallel I/O port
-- File name : ioport.vhd
--
-- www.OpenCores.Org - September 2003
-- This core adheres to the GNU public license
-- Purpose : Implements a dual 8 bit bidirectional I/O port
--
-- 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
--
-- ioport.vhd is a dual bi-directional 8 bit I/O port written in VHDL.
--
-- Copyright (C) 2002 - 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 Author Date Description
-- 0.1 John E. Kent 11 October 2002 Used a loop counter for
-- data direction & read port signals
-- 0.2 John E. Kent 5 September 2003 Reduced to 2 x 8 bit ports
-- 1.0 John E. Kent 6 September 2003 Changed Clock Edge
-- 1.1 John E. Kent 25 Februrary 2007 Modified sensitivity lists
-- 1.2 John E. Kent 30 May 2010 Updated Header, added unisim library
--
-- File name : ioport.vhd
--
-- Purpose : dual 8 bit I/O module for System09
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
--
-- Uses : None
--
-- Author : John E. Kent
-- dilbert57@opencores.org
--
--===========================================================================----
--
-- Revision History:
--===========================================================================--
--
-- Version 0.1 - 11 Oct 2002
-- Used a loop counter for data direction & read port signals
-- Version 0.2 - 5 Sept 2003
-- Reduced to 2 x 8 bit ports
-- Version 1.0 - 6 Sept 2003 - John Kent
-- Realeased to open Cores
-- changed Clock Edge
-- Version 1.1 - 25 Feb 2007 - John Kent
-- modified sensitivity lists
--
--===========================================================================
--
 
38,6 → 55,8
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
library unisim;
use unisim.vcomponents.all;
 
entity ioport is
port (
/bit_funcs.vhd
1,28 → 1,76
--===========================================================================--
-- --
-- bit_funcs.vhd - Power2 & Log2 Funtions Package --
-- --
--===========================================================================--
--
-- File name : bit_funcs.vhd
--
-- Purpose : Implements power2 and log2 functions.
--
-- Dependencies : ieee.std_logic_1164
-- ieee.std_logic_arith
-- ieee.std_logic_unsigned
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- bit_func.vhd is a VHDL functions package for calulating power2 and log2.
--
-- 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 --
-- --
--===========================================================================--
--
-- Revision Name Date Description
-- 0.1 John E. Kent unknown Initial version
-- 1.0 John E. Kent 30th May 2010 Added GPL Header
--
 
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
 
 
package bit_funcs is
function log2(v: in natural) return natural;
function pow2(v: in natural) return natural;
end package bit_funcs;
end package bit_funcs;
 
package body bit_funcs is
function log2(v: in natural) return natural is
variable i: natural;
variable n: natural;
variable logn: natural;
begin
n := 1;
for i in 0 to 128 loop
logn := i;
exit when (n>=v);
n := n * 2;
end loop;
return logn;
end function log2;
 
package body bit_funcs is
 
 
function log2 (v : in natural) return natural is
variable temp, log: natural;
begin
temp := v / 2;
log := 0;
while (temp /= 0) loop
temp := temp/2;
log := log + 1;
end loop;
return log;
end function log2;
 
function pow2(v: in natural) return natural is
variable i: natural;
variable pown: natural;
/unicpu09.vhd
1,116 → 1,141
--===========================================================================----
--===========================================================================--
-- --
-- Synthesizable Single 6809 Instruction Compatible CPU Module --
-- --
--===========================================================================--
--
-- S Y N T H E Z I A B L E unicpu09.vhd - Single 6809 processor core
-- File name : unicpu09.vhd
--
--===========================================================================----
-- Purpose : Implements a single 6809 CPU module with
-- Dynamic Address Translation
-- CPU Module ID register and
-- 32 bit Hardware Multiplier register
--
-- Dependencies : ieee.std_logic_1164
-- ieee.std_logic_unsigned
-- ieee.std_logic_arith
-- ieee.numeric_std
-- unisim.vcomponents
--
-- Uses : cpu09 (cpu09.vhd) 6809 CPU core
-- mmu (mmu.vhd) Memory Management Unit
-- mul32 (mul32.vhd) 32 bit hardware multiplier
--
-- This core adheres to the GNU public license
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
--
-- 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 Author Date Changes
--
-- 0.1 John Kent 2003-03-20 Started work on design (?)
-- 0.2 John Kent 2010-06-16 Updated header with GPL
--
-- File name : System09.vhd
--
-- Purpose : Top level file for Hex Core 6809 compatible system on a chip
-- Designed with Xilinx XC3S1000 Spartan 3 FPGA.
-- Implemented With Digilent Xilinx Starter FPGA board,
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
-- ieee.std_logic_arith
-- ieee.numeric_std
--
-- Uses :
-- cpu09 (cpu09.vhd) 6809 CPU core
--
-- Author : John E. Kent
-- dilbert57@opencores.org
--
--===========================================================================----
--
-- Revision History:
--
--===========================================================================--
-- Version 0.1 - 20 March 2003
--
--===========================================================================--
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
library unisim;
use unisim.vcomponents.all;
 
entity unicpu09 is
 
port(
entity unicpu09 is
port
(
clk : in std_logic;
rst : in std_logic;
rst : in std_logic;
--
-- cpu side signals
--
-- cpu side signals
--
id : in std_logic_vector( 7 downto 0);
vma : out std_logic;
rw : out std_logic;
vma : out std_logic;
addr : out std_logic_vector(19 downto 0);
id : in std_logic_vector( 7 downto 0);
--
-- memory side signals
--
-- memory side signals
mem_vma : in std_logic;
mem_rw : in std_logic;
mem_addr : in std_logic_vector(19 downto 0);
mem_data_in : in std_logic_vector(7 downto 0);
mem_data_out : out std_logic_vector(7 downto 0);
--
-- controls
--
mem_rw : in std_logic;
mem_vma : in std_logic;
mem_addr : in std_logic_vector(19 downto 0);
mem_dati : in std_logic_vector(7 downto 0);
mem_dato : out std_logic_vector(7 downto 0);
--
-- controls
--
halt : in std_logic;
hold : in std_logic;
irq : in std_logic;
nmi : in std_logic;
firq : in std_logic
);
);
end entity;
 
-------------------------------------------------------------------------------
-- Architecture for System09
-- Architecture for unicpu09
-------------------------------------------------------------------------------
architecture RTL of unicpu09 is
 
 
architecture RTL of unicpu09 is
 
-- CPU Interface signals
signal cpu_rw : std_logic;
signal cpu_vma : std_logic;
signal cpu_addr : std_logic_vector(15 downto 0);
signal cpu_dati : std_logic_vector(7 downto 0);
signal cpu_dato : std_logic_vector(7 downto 0);
 
signal cpu_data_in : std_logic_vector(7 downto 0);
signal cpu_data_out : std_logic_vector(7 downto 0);
 
-- BOOT ROM
signal rom_cs : Std_logic;
signal rom_dato : Std_Logic_Vector(7 downto 0);
 
-- cache host signals
signal cache_cpu_addr : std_logic_vector(31 downto 0);
signal cache_cpu_dati : std_logic_vector(15 downto 0);
signal cache_cpu_dato : std_logic_vector(15 downto 0);
signal cache_cpu_vma : std_logic;
signal cache_cpu_en : std_logic;
 
-- cache memory signals
signal cache_mem_addr : std_logic_vector(31 downto 0);
signal cache_mem_dati : std_logic_vector(15 downto 0);
signal cache_mem_dato : std_logic_vector(15 downto 0);
signal cache_mem_vma : std_logic;
 
-- Dynamic Address Translation
signal dat_cs : std_logic;
signal dat_addr : std_logic_vector(15 downto 0);
 
signal rom_cs : std_logic;
signal rom_data_out : std_Logic_Vector(7 downto 0);
 
-- Memory Management Unit
signal mmu_cs : std_logic;
signal mmu_addr : std_logic_vector(26 downto 0);
 
-- 32 bit harware multiplier
signal mul_cs : std_logic;
signal mul_dato : std_logic_vector(7 downto 0);
 
signal mul_data_out : std_logic_vector(7 downto 0);
 
-- external access
signal ext_cs : std_logic;
signal ext_dato : std_logic_vector(7 downto 0);
 
signal ext_data_out : std_logic_vector(7 downto 0);
 
-- cache host signals
signal cache_hcs : std_logic;
signal cache_haddr : std_logic_vector(31 downto 0);
signal cache_hdata_in : std_logic_vector(15 downto 0);
signal cache_hdata_out : std_logic_vector(15 downto 0);
signal cache_hen : std_logic;
 
-- cache memory signals
signal cache_scs : std_logic;
signal cache_saddr : std_logic_vector(31 downto 0);
signal cache_sdata_in : std_logic_vector(15 downto 0);
signal cache_sdata_out : std_logic_vector(15 downto 0);
 
component cpu09
port (
clk : in std_logic;
127,26 → 152,25
firq : in std_logic
);
end component;
 
 
----------------------------------------
--
-- Dynamic Address Translation Registers
-- Memory Management Unit (32 x 16)
--
----------------------------------------
component dat_ram
component mmu
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr_lo : in std_logic_vector(3 downto 0);
addr_hi : 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)
addr : in std_logic_vector(15 downto 0);
data_in : in std_logic_vector( 7 downto 0);
addr_out : out std_logic_vector(26 downto 0)
);
end component;
 
 
 
----------------------------------------
--
-- 4KByte Block RAM Monitor ROM
159,35 → 183,41
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector (11 downto 0);
rdata : out std_logic_vector (7 downto 0);
wdata : in std_logic_vector (7 downto 0)
data_in : in std_logic_vector (7 downto 0);
data_out : out std_logic_vector (7 downto 0)
);
end component;
 
 
----------------------------------------
--
-- Dual Port cache memory
-- Dual Port Cache memory 2K x 8 Bit
--
----------------------------------------
component dpr_2k
port (
clk_a : in std_logic;
rst_a : in std_logic;
cs_a : in std_logic;
rw_a : in std_logic;
addr_a : in std_logic_vector (9 downto 0);
dati_a : in std_logic_vector (15 downto 0);
dato_a : out std_logic_vector (15 downto 0);
clk_b : in std_logic;
rst_b : in std_logic;
cs_b : in std_logic;
rw_b : in std_logic;
addr_b : in std_logic_vector (9 downto 0);
dati_b : in std_logic_vector (15 downto 0);
dato_b : out std_logic_vector (15 downto 0)
);
end component;
 
component dpr_2k
port (
--
-- Port A (Host)
--
clk_a : in std_logic;
rst_a : in std_logic;
cs_a : in std_logic;
rw_a : in std_logic;
addr_a : in std_logic_vector (10 downto 0);
data_in_a : in std_logic_vector ( 7 downto 0);
data_out_a : out std_logic_vector ( 7 downto 0);
--
-- Port B (Slave)
--
clk_b : in std_logic;
rst_b : in std_logic;
cs_b : in std_logic;
rw_b : in std_logic;
addr_b : in std_logic_vector (10 downto 0);
data_in_b : in std_logic_vector ( 7 downto 0);
data_out_b : out std_logic_vector ( 7 downto 0)
);
end component;
 
----------------------------------------
--
-- 32 bit hardware multiplier
200,8 → 230,8
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector(3 downto 0);
dati : in std_logic_vector(7 downto 0);
dato : out std_logic_vector(7 downto 0)
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0)
);
end component;
 
216,8 → 246,8
rw => cpu_rw,
vma => cpu_vma,
address => cpu_addr(15 downto 0),
data_in => cpu_dati,
data_out => cpu_dato,
data_in => cpu_data_in,
data_out => cpu_data_out,
halt => halt,
hold => hold,
irq => irq,
224,16 → 254,15
nmi => nmi,
firq => firq
);
 
my_dat : dat_ram port map (
 
my_mmu : mmu port map (
clk => clk,
rst => rst,
cs => dat_cs,
cs => mmu_cs,
rw => cpu_rw,
addr_hi => cpu_addr(15 downto 12),
addr_lo => cpu_addr(3 downto 0),
data_in => cpu_dato,
data_out => dat_addr(7 downto 0)
addr => cpu_addr,
data_in => cpu_data_out,
addr_out => mmu_addr
);
 
my_rom : mon_rom port map (
242,68 → 271,89
cs => rom_cs,
rw => '1',
addr => cpu_addr(11 downto 0),
rdata => rom_dato,
wdata => cpu_dato
data_in => cpu_data_out,
data_out => rom_data_out,
);
--
-- high address cache
--
my_dpr_0 : dpr_2k port map (
clk_a => clk,
rst_a => rst,
cs_a => cpu_vma,
rw_a => '0',
addr_a => cpu_addr(9 downto 0),
dati_a => dat_addr(15 downto 0),
dato_a => cache_cpu_addr(31 downto 16),
clk_b => clk,
rst_b => rst,
cs_b => mem_vma,
rw_b => '1',
addr_b => mem_addr(9 downto 0),
dati_b => (others=>'0'),
dato_b => cache_mem_addr(31 downto 16)
);
--
-- low address cache
--
my_dpr_1 : dpr_2k port map (
clk_a => clk,
rst_a => rst,
cs_a => cpu_vma,
rw_a => '0',
addr_a => cpu_addr(9 downto 0),
dati_a => cpu_addr(15 downto 0),
dato_a => cache_cpu_addr(15 downto 0),
clk_b => clk,
rst_b => rst,
cs_b => mem_vma,
rw_b => '1',
addr_b => mem_addr(9 downto 0),
dati_b => (others=>'0'),
dato_b => cache_mem_addr(15 downto 0)
);
 
--
-- data cache
--
my_dpr_2 : dpr_2k port map (
clk_a => clk,
rst_a => rst,
cs_a => cache_cpu_vma,
rw_a => cpu_rw,
addr_a => cpu_addr(9 downto 0),
dati_a => cache_cpu_dati(15 downto 0),
dato_a => cache_cpu_dato(15 downto 0),
clk_b => clk,
rst_b => rst,
cs_b => cache_mem_vma,
rw_b => mem_rw,
addr_b => mem_addr(9 downto 0),
dati_b => cache_mem_dati(15 downto 0),
dato_b => cache_mem_dato(15 downto 0)
);
 
 
--
-- High Address Cache
--
my_dpr_0 : dpr_2k port map (
--
-- Port A (Host / CPU interface)
--
clk_a => clk,
rst_a => rst,
cs_a => cpu_vma,
rw_a => '0',
addr_a => cpu_addr(10 downto 0),
data_in_a => mmu_addr(26 downto 19),
data_out_a => cache_haddr(26 downto 19),
--
-- Port B (Slave / Memory Interface)
--
clk_b => clk,
rst_b => rst,
cs_b => mem_vma,
rw_b => '1',
addr_b => mem_addr(10 downto 0),
data_in_b => (others => '0'),
data_out_b => cache_saddr(26 downto 19)
);
 
--
-- Low Address cache
--
my_dpr_1 : dpr_2k port map (
--
-- Port A (Host / CPU interface)
--
clk_a => clk,
rst_a => rst,
cs_a => cpu_vma,
rw_a => '0',
addr_a => cpu_addr(10 downto 0),
data_in_a => mmu_addr(18 downto 11),
data_out_a => cache_haddr(18 downto 11),
--
-- Port B (Slave / Memory Interface)
--
clk_b => clk,
rst_b => rst,
cs_b => mem_vma,
rw_b => '1',
addr_b => mem_addr(10 downto 0),
data_in_b => (others => '0'),
data_out_b => cache_saddr(18 downto 11)
);
 
 
--
-- data cache
--
my_dpr_2 : dpr_2k port map (
--
-- Port A (Host / CPU Interface)
--
clk_a => clk,
rst_a => rst,
cs_a => cache_hcs,
rw_a => cpu_rw,
addr_a => cpu_addr(10 downto 0),
data_in_a => cache_hdata_in(7 downto 0),
data_out_a => cache_hdata_out(7 downto 0),
--
-- Port B (Slave / Memory Interface)
--
clk_b => clk,
rst_b => rst,
cs_b => cache_scs,
rw_b => mem_rw,
addr_b => mem_addr(10 downto 0),
data_in_b => cache_sdata_in(7 downto 0),
data_out_b => cache_sdata_out(7 downto 0)
);
 
my_mul32 : mul32 port map (
clk => clk,
rst => rst,
310,10 → 360,10
cs => mul_cs,
rw => cpu_rw,
addr => cpu_addr(3 downto 0),
dati => cpu_dato,
dato => mul_dato
data_in => cpu_data_out,
data_out => mul_data_out
);
 
 
----------------------------------------------------------------------
--
-- Process to decode internal registers
320,123 → 370,128
--
----------------------------------------------------------------------
 
int_decode: process( cpu_addr, cpu_rw, cpu_vma,
cache_cpu_dato,
dat_cs, dat_addr,
cache_cpu_dato,
mul_dato,
rom_dato
uni_decode: process( cpu_addr, cpu_rw, cpu_vma,
cache_hdata_out,
dat_cs, dat_addr,
cache_hdata_out,
mul_data_out,
rom_data_out
)
begin
cpu_dati <= cache_cpu_dato( 7 downto 0);
cache_cpu_en <= '1';
begin
--
-- By default CPU accesses memory cache
--
cpu_data_in <= cache_hdata_out( 7 downto 0);
cache_hen <= '1'; -- Cache enabled by default
ext_cs <= cpu_vma; -- Assume external access
dat_cs <= '0'; -- Dynamic Address Translation
rom_cs <= '0';
dat_cs <= '0'; -- Dynamic Address Translation
rom_cs <= '0'; -- Monitor ROM
mul_cs <= '0'; -- Hardware Multiplier
 
if cpu_addr( 15 downto 8 ) = "11111111" then
--
-- DAT write registers at $FFF0 to $FFFF
if cpu_addr( 15 downto 8 ) = "11111111" then
--
-- DAT write registers at $FFF0 to $FFFF
--
cpu_dati <= rom_dato;
rom_cs <= cpu_vma;
dat_cs <= cpu_vma;
cpu_data_in <= rom_data_out;
rom_cs <= cpu_vma;
dat_cs <= cpu_vma;
ext_cs <= '0';
cache_cpu_en <= '0';
cache_hen <= '0';
--
-- ROM $F000 - $FFFF
--
elsif dat_addr(3 downto 0) = "1111" then -- $XE000 - $XEFFF
cpu_dati <= rom_dato;
rom_cs <= cpu_vma;
cache_cpu_en <= '0';
elsif dat_addr(3 downto 0) = "1111" then -- $XE000 - $XEFFF
cpu_data_in <= rom_data_out;
rom_cs <= cpu_vma;
cache_hen <= '0';
--
-- IO Devices $E000 - $EFFF
--
elsif dat_addr(3 downto 0) = "1110" then -- $XE000 - $XEFFF
--
-- disable cache for I/O
--
cache_cpu_en <= '0';
 
elsif dat_addr(3 downto 0) = "1110" then -- $XE000 - $XEFFF
--
-- disable cache for I/O
--
cache_hen <= '0';
 
case cpu_addr(11 downto 8) is
--
-- CPU specific registers from $E200 to $E2FF
--
when "0010" =>
ext_cs <= '0'; -- assume this segment is internal
cpu_dati <= (others=>'0'); -- default to null data
--
-- Unique number to identify CPU
--
ext_cs <= '0'; -- assume this segment is internal
cpu_data_in <= (others=>'0'); -- default to null data
 
--
-- Module ID number
--
case cpu_addr(7 downto 4) is
when "0000" =>
cpu_dati <= cpu_id; -- CPU ID register
--
-- hardware 32 bit multiplier
--
cpu_data_in <= id; -- unicpu module ID
 
--
-- hardware 32 bit multiplier
--
when "0001" =>
cpu_dati <= mul_dato; -- Hardware Multiplier register
mul_cs <= cpu_vma;
 
cpu_data_in <= mul_data_out; -- Hardware Multiplier register
mul_cs <= cpu_vma;
 
when others =>
null;
end case;
 
 
--
-- Everything else is external
--
when others =>
when others =>
null;
end case;
end case;
end if;
end process;
 
--
-- cpu side cache controller
--
my_cpu_cache : process( cpu_vma, cpu_rw, cpu_data_out, cpu_addr, dat_addr,
cache_haddr, cache_hen, ext_cs )
begin
dat_addr(15 downto 8) <= (others=>'0');
addr(19 downto 12) <= dat_addr xor id;
addr(11 downto 0) <= cpu_addr(11 downto 0);
rw <= cpu_rw;
vma <= '0';
--
-- external access if cache miss or write through or if i/o space
--
if (cache_haddr(23 downto 16) /= dat_addr( 7 downto 0) ) or
(cache_haddr(11 downto 0) /= cpu_addr(11 downto 0) ) or
(cpu_rw = '0') or (cache_hen = '0') then
vma <= ext_cs;
end if;
cache_hdata_in( 7 downto 0) <= cpu_data_out;
cache_hdata_in(15 downto 8) <= (others=>'0');
end process;
 
--
-- memory side cache controller
--
my_mem_cache : process( mem_vma, mem_addr, mem_data_in, mem_rw,
cache_saddr, cache_sdata_out )
begin
--
-- write through from another CPU will update cache entry
-- if there is a cache hit
--
cache_scs <= '0';
if (cache_saddr(23 downto 16) = mem_addr(19 downto 12)) and
(cache_saddr(11 downto 0) = mem_addr(11 downto 0)) then
cache_scs <= mem_vma;
end if;
mem_data_out <= cache_sdata_out( 7 downto 0);
cache_sdata_in( 7 downto 0) <= mem_data_in;
cache_sdata_in(15 downto 8) <= (others=>'0');
end process;
 
end architecture;
 
--
-- cpu side cache controller
--
my_cpu_cache : process( cpu_vma, cpu_rw, cpu_dato, cpu_addr, dat_addr,
cache_cpu_addr, cache_cpu_en, ext_cs )
begin
dat_addr(15 downto 8) <= (others=>'0');
addr(19 downto 12) <= dat_addr xor id;
addr(11 downto 0) <= cpu_addr(11 downto 0);
rw <= cpu_rw;
vma <= '0';
--
-- external access if cache miss or write through or if i/o space
--
if (cache_cpu_addr(23 downto 16) /= dat_addr( 7 downto 0) ) or
(cache_cpu_addr(11 downto 0) /= cpu_addr(11 downto 0) ) or
(cpu_rw = '0') or (cache_cpu_en = '0') then
vma <= ext_cs;
end if;
cache_cpu_dati( 7 downto 0) <= cpu_dato;
cache_cpu_dati(15 downto 8) <= (others=>'0');
end process;
 
--
-- memory side cache controller
--
my_mem_cache : process( mem_vma, mem_addr, mem_dati, mem_rw,
cache_mem_addr, cache_mem_dato )
begin
--
-- write through from another CPU will update cache entry
-- if there is a cache hit
--
cache_mem_vma <= '0';
if (cache_mem_addr(23 downto 16) = mem_addr(19 downto 12)) and
(cache_mem_addr(11 downto 0) = mem_addr(11 downto 0)) then
cache_mem_vma <= mem_vma;
end if;
mem_dato <= cache_mem_dato( 7 downto 0);
cache_mem_dati( 7 downto 0) <= mem_dati;
cache_mem_dati(15 downto 8) <= (others=>'0');
end process;
 
end architecture;
 
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
/vdu8_mono.vhd
1,25 → 1,122
-- ---------------------------------------------------
-- Video Display terminal
-- ---------------------------------------------------
-- John Kent
-- 3th September 2004
-- Assumes a pixel clock input of 25 MHz
--===========================================================================--
-- --
-- vdu8_mono.vhd - Synthesizable Monochrome Video Display Unit for System09 --
-- --
--===========================================================================--
--
-- Display Format is:
-- 80 characters across by 25 characters down.
-- 8 horizontal pixels / character
-- 16 vertical scan lines / character (2 scan lines/row)
-- File name : vdu8.vhd
--
-- Modified by Bert Cuzeau for compliance and code cleanliness
-- The effort is not over.
-- There are still signal initialized, which is BAD.
-- Purpose : Implements a text based Monochrome Video Display Unit for System09
-- Supports 2KByte Text buffer.
-- Displays 80 characters across by 25 character rows
-- Characters are 8 pixels across x 16 lines down.
-- Uses Generic arguments for setting the video synchronization timing.
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
-- ieee.std_logic_arith
-- ieee.numeric_std
--
-- 3rd February 2007 - John Kent
-- changed vdu_clk to be derived externally from cpu_clk.
-- Removed attibute memory for monochrome character only version.
-- Uses : ram_2k (ram2k_b16.vhd) 2KByte Character Buffer
-- char_rom (char_rom2k_b16.vhd) 2KByte Character Generator
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- Description : Display Timing:
-- 800 pixels / line
-- 446 lines / frame
-- None interlaced
-- 25MHz pixel clock implies
-- 31.25 KHz line rate
-- 70.067 Hz frame rate
-- Timing settable by generics.
--
-- Display Size:
-- 80 characters across
-- 25 characters down.
--
-- Character Size:
-- 8 horizontal pixels across
-- 16 vertical scan lines down (2 scan lines/row)
--
-- Registers:
-- Base + 0 ASCII character register
-- Writing to this register writes an 8 bit byte
-- into the text buffer at the specified cursor position
-- Text Mode: ASCII Character (0 to 127)
-- Chunky Graphics Mode: B0 B1 (0 to 255)
-- B2 B3
-- B4 B5
-- B6 B7
-- Base + 1 Reserved Attibute bit (0 to 255)
-- Base + 2 Cursor Horizontal Position (0 to 79)
-- Base + 3 Cusror Vertical Position (0 to 24)
-- Base + 4 Vertical Scroll Offset (0 to 24)
-- Scrolls the display up by the specified number of character rows
-- Video Timing :
--
-- Horizontal 800 Pixels/ 25MHz Pixel Clock = 32usec Line period = 31.25 KHz Line Frequency
-- /--------------------------\_____________/---------------\______________/
-- 640 Pixels Display 16 Pixel FP 96 Pixel HS 48 Pixel BP
--
-- VGA_CLK_FREQ : integer := 25000000; -- HZ
-- VGA_HOR_FRONT_PORCH : integer := 16; -- PIXELS 0.64us (0.94us)
-- VGA_HOR_SYNC : integer := 96; -- PIXELS 3.84us (3.77us)
-- VGA_HOR_BACK_PORCH : integer := 48; -- PIXELS 1.92us (1.89us)
-- VGA_PIX_PER_CHAR : integer := 8; -- PIXELS 0.32us
-- VGA_HOR_CHARS : integer := 80; -- CHARACTERS 25.6us
--
-- Vertical 446 Lines * 32 usec Line rate = 14.272ms Frame Period = 70.07Hz Frame frequency
-- /---------------------------\____________/---------------\______________/
-- 400 Line Display 10 Line FP 2 Line VS 34 Line BP
--
-- VGA_VER_FRONT_PORCH : integer := 10; -- LINES 0.320ms
-- VGA_VER_SYNC : integer := 2; -- LINES 0.064ms
-- VGA_VER_BACK_PORCH : integer := 34; -- LINES 1.088ms
-- VGA_LIN_PER_CHAR : integer := 16; -- LINES 0.512ms
-- VGA_VER_CHARS : integer := 25; -- CHARACTERS 12.8ms
--
-- 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 Author Date Changes
--
-- 1st July 20007 - John Kent
-- Added generics for timing specification.
-- 0.1 John Kent 2004-09-03 Initial release
--
-- 0.2 Bert Cuzeau 2007-01-16 Modified by for compliance and code cleanliness
-- The effort is not over.
-- There are still signal initialized, which is BAD.
--
-- 0.3 John Kent 2007-02-03 Changed vdu_clk to be derived externally from cpu_clk.
-- Removed attibute memory for monochrome character only version.
-- This was done to reduce Bock RAM allocation
--
-- 0.4 John Kent 2007-07-01 Added generics for VGA timing specification
--
-- 0.5 John Kent 2010-07-03 Added GPL notice.
-- Updated description
--
 
Library IEEE;
30,18 → 127,17
 
Entity vdu8_mono is
generic(
VDU_CLOCK_FREQUENCY : integer := 12500000; -- HZ
VGA_CLOCK_FREQUENCY : integer := 25000000; -- HZ
VGA_HOR_CHARS : integer := 80; -- CHARACTERS
VGA_VER_CHARS : integer := 25; -- CHARACTERS
VGA_PIXELS_PER_CHAR : integer := 8; -- PIXELS
VGA_LINES_PER_CHAR : integer := 16; -- LINES
VGA_HOR_BACK_PORCH : integer := 40; -- PIXELS
VGA_HOR_SYNC : integer := 96; -- PIXELS
VGA_HOR_FRONT_PORCH : integer := 24; -- PIXELS
VGA_VER_BACK_PORCH : integer := 13; -- LINES
VGA_VER_SYNC : integer := 1; -- LINES
VGA_VER_FRONT_PORCH : integer := 36 -- LINES
VGA_CLK_FREQ : integer := 25000000; -- HZ
VGA_HOR_CHARS : integer := 80; -- CHARACTERS 25.6us
VGA_HOR_CHAR_PIXELS : integer := 8; -- PIXELS 0.32us
VGA_HOR_FRONT_PORCH : integer := 16; -- PIXELS 0.64us
VGA_HOR_SYNC : integer := 96; -- PIXELS 3.84us
VGA_HOR_BACK_PORCH : integer := 48; -- PIXELS 1.92us
VGA_VER_CHARS : integer := 25; -- CHARACTERS 12.8ms
VGA_VER_CHAR_LINES : integer := 16; -- LINES 0.512ms
VGA_VER_FRONT_PORCH : integer := 10; -- LINES 0.320ms
VGA_VER_SYNC : integer := 2; -- LINES 0.064ms
VGA_VER_BACK_PORCH : integer := 34 -- LINES 1.088ms
);
port(
-- control register interface
71,24 → 167,24
-- Displayed Characters per row
constant HOR_DISP_CHR : integer := VGA_HOR_CHARS;
-- Last horizontal pixel displayed
constant HOR_DISP_END : integer := (HOR_DISP_CHR * VGA_PIXELS_PER_CHAR) - 1;
constant HOR_DISP_END : integer := (HOR_DISP_CHR * VGA_HOR_CHAR_PIXELS) - 1;
-- Start of horizontal synch pulse
constant HOR_SYNC_BEG : integer := HOR_DISP_END + VGA_HOR_BACK_PORCH;
constant HOR_SYNC_BEG : integer := HOR_DISP_END + VGA_HOR_FRONT_PORCH;
-- End of Horizontal Synch pulse
constant HOR_SYNC_END : integer := HOR_SYNC_BEG + VGA_HOR_SYNC;
-- Last pixel in scan line
constant HOR_SCAN_END : integer := HOR_SYNC_END + VGA_HOR_FRONT_PORCH;
constant HOR_SCAN_END : integer := HOR_SYNC_END + VGA_HOR_BACK_PORCH;
 
-- Displayed Characters per Column
constant VER_DISP_CHR : integer := VGA_VER_CHARS;
-- last row displayed
constant VER_DISP_END : integer := (VER_DISP_CHR * VGA_LINES_PER_CHAR) - 1;
constant VER_DISP_END : integer := (VER_DISP_CHR * VGA_VER_CHAR_LINES) - 1;
-- start of vertical synch pulse
constant VER_SYNC_BEG : integer := VER_DISP_END + VGA_VER_BACK_PORCH;
constant VER_SYNC_BEG : integer := VER_DISP_END + VGA_VER_FRONT_PORCH;
-- end of vertical synch pulse
constant VER_SYNC_END : integer := VER_SYNC_BEG + VGA_VER_SYNC;
-- Last scan row in the frame
constant VER_SCAN_END : integer := VER_SYNC_END + VGA_VER_FRONT_PORCH;
constant VER_SCAN_END : integer := VER_SYNC_END + VGA_VER_BACK_PORCH;
 
signal horiz_sync : std_logic := '1';
signal vert_sync : std_logic := '1';
157,8 → 253,8
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector (10 downto 0);
wdata : in std_logic_vector (7 downto 0);
rdata : out std_logic_vector (7 downto 0)
data_in : in std_logic_vector (7 downto 0);
data_out : out std_logic_vector (7 downto 0)
);
end component;
 
167,11 → 263,10
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
-- r_wn : in std_logic;
rw : in std_logic;
addr : in std_logic_vector (10 downto 0);
wdata : in std_logic_vector (7 downto 0);
rdata : out std_logic_vector (7 downto 0)
data_in : in std_logic_vector (7 downto 0);
data_out : out std_logic_vector (7 downto 0)
);
end component;
 
186,8 → 281,8
cs => '1',
rw => '1',
addr => char_addr,
wdata => "00000000",
rdata => char_data_out
data_in => "00000000",
data_out => char_data_out
);
 
--
197,11 → 292,10
clk => vga_clk,
rst => vdu_rst,
cs => vga_cs,
-- r_wn => vga_rw,
rw => vga_rw,
addr => vga_addr,
wdata => reg_character,
rdata => vga_data_out
data_in => reg_character,
data_out => vga_data_out
);
 
--
/epp.vhd
1,182 → 1,211
--===========================================================================----
--
-- S Y N T H E Z I A B L E epp - Enhanced Parallel Port
--
-- www.OpenCores.Org - September 2003
-- This core adheres to the GNU public license
--
-- File name : epp.vhd
--
-- Purpose : Simple Parallel Port for System09
--
-- Dependencies : ieee.Std_Logic_1164
-- ieee.std_logic_unsigned
--
-- Uses : None
--
-- Author : John E. Kent
-- dilbert57@opencores.org
--
--===========================================================================----
--
-- Revision History:
--===========================================================================--
--
-- Version 0.1 - 6th Sep 2008
-- Generated from ioport.vhd
--
--===========================================================================
--
-- Parallel printer port pin assignment
--
-- Pin No (DB25) SPP Signal EPP Signal Direction Register Bit Inverted
-- 1 nStrobe Write_n Out Control-0 Yes
-- 2 Data0 Data0 In/Out Data-0 No
-- 3 Data1 Data1 In/Out Data-1 No
-- 4 Data2 Data2 In/Out Data-2 No
-- 5 Data3 Data3 In/Out Data-3 No
-- 6 Data4 Data4 In/Out Data-4 No
-- 7 Data5 Data5 In/Out Data-5 No
-- 8 Data6 Data6 In/Out Data-6 No
-- 9 Data7 Data7 In/Out Data-7 No
-- 10 nAck Interrupt In Status-6 No
-- 11 Busy Wait In Status-7 Yes
-- 12 Paper-Out Spare In Status-5 No
-- 13 Select Spare In Status-4 No
--
-- 14 Linefeed Data_Strobe_n Out Control-1 Yes
-- 15 nError Spare In Status-3 No
-- 16 nInitialize Reset Out Control-2 No
-- 17 nSelect-Printer Addr_Strobe_n Out Control-3 Yes
-- 18-25 Ground Ground - - -
--
-- Address MSB LSB
-- Bit: 7 6 5 4 3 2 1 0
-- Base (SPP Data port) Write Pin: 9 8 7 6 5 4 3 2
-- Base+1 (SPP Status port) Read Pin: ~11 10 12 13 15
-- Base+2 (SPP Control port) Write Pin: ~17 16 ~14 ~1
-- Base+3 (EPP Address port) R/W
-- Base+4 (EPP Data port) R/W
--
-- ~ indicates a hardware inversion of the bit.
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity epp is
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector(2 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
epp_data : out std_logic_vector(7 downto 0);
epp_stat : in std_logic_vector(7 downto 3);
epp_ctrl : out std_logic_vector(3 downto 0);
hold : out std_logic;
irq : out std_logic
);
end;
 
architecture rtl of epp is
 
constant CTRL_RW_BIT : integer := 0;
constant CTRL_DS_BIT : integer := 1;
constant CTRL_RS_BIT : integer := 2;
constant CTRL_AS_BIT : integer := 3;
 
constant STAT_IR_BIT : integer := 6;
constant STAT_WT_BIT : integer := 7;
 
signal epp_ctrl_reg : std_logic_vector(3 downto 0);
 
begin
 
--
-- Read / Write control
--
epp_control : process( rst, clk, cs, rw, addr, epp_stat, epp_crl_reg, data_in )
begin
if rst = '1' then
epp_ctrl_reg(CTRL_RW_BIT) <= '1';
epp_ctrl_reg(CTRL_AS_BIT) <= '1';
epp_ctrl_reg(CTRL_RS_BIT) <= '0';
epp_ctrl_reg(CTRL_DS_BIT) <= '1';
epp_data <= (others=>'Z');
--
-- clock controls on rising edge
--
elsif clk'event and clk = '1' then
epp_ctrl_reg(CTRL_RS_BIT) <= '1';
 
if cs = '1' then
case addr is
--
-- address register
--
when "011" =>
--
-- set Data port direction
--
if rw = '1' then
epp_ctrl_reg(CTRL_RW_BIT) <= '1';
epp_data <= (others=>'Z');
else
epp_ctrl_reg(CTRL_RW_BIT) <= '0';
epp_data <= data_in;
end if;
--
-- initiale an address strobe
--
if epp_stat(STAT_WT_BIT) = '0' then
epp_ctrl_reg(CTRL_AS_BIT) <= '0';
elsif epp_stat(STAT_WT_BIT) = '1' then
epp_ctrl_reg(CTRL_AS_BIT) <= '1';
end if;
 
--
-- data register
--
when "100" =>
--
-- set data port direction
--
if rw = '1' then
epp_ctrl_reg(CTRL_RW_BIT) <= '1';
epp_data <= (others=>'Z');
else
epp_ctrl_reg(CTRL_RW_BIT) <= '0';
epp_data <= data_in;
end if;
--
-- initiate a data strobe
--
if epp_stat(STAT_WT_BIT) = '0' then
epp_ctrl_reg(CTRL_DS_BIT) <= '0';
elsif epp_stat(STAT_WT_BIT) = '1' then
epp_ctrl_reg(CTRL_DS_BIT) <= '1';
end if;
 
when others =>
epp_ctrl_reg(CTRL_RW_BIT) <= '1';
epp_ctrl_reg(CTRL_AS_BIT) <= '1';
epp_ctrl_reg(CTRL_DS_BIT) <= '1';
epp_data <= (others=>'Z');
null;
 
end case; -- addr
end if; -- cs
end if; -- clk / reset
irq <= epp_stat(STAT_IR_BIT);
hold <= not( epp_ctrl_reg(CTRL_DS_BIT) ) or not( epp_ctrl_reg(CTRL_AS_BIT) );
epp_ctrl <= epp_ctrl_reg;
data_out <= epp_data;
 
end process;
 
end rtl;
--===========================================================================--
-- --
-- Synthesizable Enhance Parallel Port --
-- --
--===========================================================================--
--
-- File name : epp.vhd
--
-- Entity name : epp
--
-- Purpose : Implements an Enhanced Parallel Port Interface
--
-- 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
--
-- Description : Register Memory Map
--
-- Address MSB LSB
-- Bit: 7 6 5 4 3 2 1 0
-- Base+$00 (SPP Data port) Write Pin: 9 8 7 6 5 4 3 2
-- Base+$01 (SPP Status port) Read Pin: ~11 10 12 13 15
-- Base+$02 (SPP Control port) Write Pin: ~17 16 ~14 ~1
-- Base+$03 (EPP Address port) R/W
-- Base+$04 (EPP Data port) R/W
--
-- ~ indicates a hardware inversion of the bit.
--
-- Parallel printer port pin assignment
--
-- Pin No (DB25) SPP Signal EPP Signal Direction Register Bit Inverted
-- 1 nStrobe Write_n Out Control-0 Yes
-- 2 Data0 Data0 In/Out Data-0 No
-- 3 Data1 Data1 In/Out Data-1 No
-- 4 Data2 Data2 In/Out Data-2 No
-- 5 Data3 Data3 In/Out Data-3 No
-- 6 Data4 Data4 In/Out Data-4 No
-- 7 Data5 Data5 In/Out Data-5 No
-- 8 Data6 Data6 In/Out Data-6 No
-- 9 Data7 Data7 In/Out Data-7 No
-- 10 nAck Interrupt In Status-6 No
-- 11 Busy Wait In Status-7 Yes
-- 12 Paper-Out Spare In Status-5 No
-- 13 Select Spare In Status-4 No
-- 14 Linefeed Data_Strobe_n Out Control-1 Yes
-- 15 nError Spare In Status-3 No
-- 16 nInitialize Reset Out Control-2 No
-- 17 nSelect-Printer Addr_Strobe_n Out Control-3 Yes
-- 18-25 Ground Ground - - -
--
-- Copyright (C) 2008 - 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 --
-- --
--===========================================================================--
--
-- Revision Author Date Description
--
-- 0.1 John E. Kent 2008-09-06 initial version generated from ioport.vhd
-- 0.2 John E. Kent 2010-08-09 updated header and added GPL
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
library unisim;
use unisim.vcomponents.all;
 
entity epp is
port (
--
-- CPU Interface Signals
--
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
rw : in std_logic;
addr : in std_logic_vector(2 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_out : out std_logic_vector(7 downto 0);
irq : out std_logic;
hold : out std_logic;
--
-- Parallel Port Interface Signals
--
epp_stat : in std_logic_vector(7 downto 3);
epp_ctrl : out std_logic_vector(3 downto 0);
epp_data : out std_logic_vector(7 downto 0)
);
end;
 
architecture rtl of epp is
 
constant CTRL_RW_BIT : integer := 0;
constant CTRL_DS_BIT : integer := 1;
constant CTRL_RS_BIT : integer := 2;
constant CTRL_AS_BIT : integer := 3;
 
constant STAT_IR_BIT : integer := 6;
constant STAT_WT_BIT : integer := 7;
 
signal epp_ctrl_reg : std_logic_vector(3 downto 0);
 
begin
 
--
-- Read / Write control
--
epp_control : process( rst, clk, cs, rw, addr, epp_stat, epp_crl_reg, data_in )
begin
if rst = '1' then
epp_ctrl_reg(CTRL_RW_BIT) <= '1';
epp_ctrl_reg(CTRL_AS_BIT) <= '1';
epp_ctrl_reg(CTRL_RS_BIT) <= '0';
epp_ctrl_reg(CTRL_DS_BIT) <= '1';
epp_data <= (others=>'Z');
--
-- clock controls on rising edge
--
elsif clk'event and clk = '1' then
epp_ctrl_reg(CTRL_RS_BIT) <= '1';
 
if cs = '1' then
case addr is
--
-- address register
--
when "011" =>
--
-- set Data port direction
--
if rw = '1' then
epp_ctrl_reg(CTRL_RW_BIT) <= '1';
epp_data <= (others=>'Z');
else
epp_ctrl_reg(CTRL_RW_BIT) <= '0';
epp_data <= data_in;
end if;
--
-- initiale an address strobe
--
if epp_stat(STAT_WT_BIT) = '0' then
epp_ctrl_reg(CTRL_AS_BIT) <= '0';
elsif epp_stat(STAT_WT_BIT) = '1' then
epp_ctrl_reg(CTRL_AS_BIT) <= '1';
end if;
 
--
-- data register
--
when "100" =>
--
-- set data port direction
--
if rw = '1' then
epp_ctrl_reg(CTRL_RW_BIT) <= '1';
epp_data <= (others=>'Z');
else
epp_ctrl_reg(CTRL_RW_BIT) <= '0';
epp_data <= data_in;
end if;
--
-- initiate a data strobe
--
if epp_stat(STAT_WT_BIT) = '0' then
epp_ctrl_reg(CTRL_DS_BIT) <= '0';
elsif epp_stat(STAT_WT_BIT) = '1' then
epp_ctrl_reg(CTRL_DS_BIT) <= '1';
end if;
 
when others =>
epp_ctrl_reg(CTRL_RW_BIT) <= '1';
epp_ctrl_reg(CTRL_AS_BIT) <= '1';
epp_ctrl_reg(CTRL_DS_BIT) <= '1';
epp_data <= (others=>'Z');
null;
 
end case; -- addr
end if; -- cs
end if; -- clk / reset
irq <= epp_stat(STAT_IR_BIT);
hold <= not( epp_ctrl_reg(CTRL_DS_BIT) ) or not( epp_ctrl_reg(CTRL_AS_BIT) );
epp_ctrl <= epp_ctrl_reg;
data_out <= epp_data;
 
end process;
 
end rtl;

powered by: WebSVN 2.1.0

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