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; |
|