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

Subversion Repositories System09

Compare Revisions

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

Rev 99 → Rev 100

/peripheral_bus.vhd
0,0 → 1,304
--===========================================================================--
-- --
-- Peripheral Bus Interface --
-- --
--===========================================================================--
--
-- File name : peripheral_bus.vhd
--
-- Entity name : peripheral_bus
--
-- Purpose : Implements a 16 bit peripheral bus interface
-- On the XESS XST-3.0 carrier board it is shared
-- by an IDE interface, and Ethernet MAC
-- and two 16 bit expansion slots.
-- The same bus structure is used on the
-- BurchED B3 and B5-X300 Spartan 2 boards
-- to implement an IDE Compact Flash interface.
--
-- The 16 bit data bus is accessed by two
-- consecutive byte wide read or write cycles.
--
-- On an even byte read a read strobe is generated
-- on the peripheral bus and the high bits of the
-- peripheral data bus are output to the CPU
-- data bus and the lower 8 bits latched.
-- A bus hold cycle is generated to allow time
-- for the peripheral data bus to settle.
-- On the odd byte read, the latched lower data
-- bits of the peripheral bus are output on the
-- CPU data bus.
--
-- Conversely, on an even byte write the CPU data
-- bus value is latched. On the odd byte write, the
-- latched value is output to the high 8 bits of
-- the peripheral bus, and the CPU data is output
-- to the lower 8 bits of the peripheral bus and
-- a peripheral write strobe is generated.
-- A hold signal is geneated back to the CPU to
-- allow the peripheral bus to settle.
--
-- Dependencies : ieee.std_logic_1164
-- ieee.numeric_std
-- unisim.vcomponents
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- Memory Map :
--
-- IO address + $00 IDE Compact Flash interface
-- IO address + $40 Ethernet MAC interface (XESS XST-3.0)
-- IO address + $80 Expansion Slot 0 (XESS XST-3.0)
-- IO address + $C0 Expansion Slot 1 (XESS XST-3.0)
--
--
-- Copyright (C) 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 2010-08-28 New model
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
library unisim;
use unisim.vcomponents.all;
 
-----------------------------------------------------------------------
-- Entity for peripheral bus --
-----------------------------------------------------------------------
 
entity peripheral_bus is
port (
--
-- CPU Interface signals
--
clk : in std_logic; -- System Clock
rst : in std_logic; -- Reset input (active high)
cs : in std_logic; -- Peripheral Bus Chip Select
addr : in std_logic_vector(7 downto 0); -- Register Select
rw : in std_logic; -- Read / Not Write
data_in : in std_logic_vector(7 downto 0); -- Data Bus In
data_out : out std_logic_vector(7 downto 0); -- Data Bus Out
hold : out std_logic; -- Hold bus cycle output
--
-- Peripheral Bus Interface Signals
-- IO + ($00 - $FF)
-- (for compatibility with XSA-3S1000 / XST 3.0)
--
pb_rd_n : out std_logic; -- ide pin 25
pb_wr_n : out std_logic; -- ide pin 23
pb_addr : out std_logic_vector( 4 downto 0);
pb_data : inout std_logic_vector(15 downto 0);
 
-- Peripheral chip selects on Peripheral Bus
ide_cs : out std_logic; -- IDE / CF interface ($00 - $3F)
eth_cs : out std_logic; -- Ethernet interface ($40 - $7F)
sl1_cs : out std_logic; -- Expansion slot 1 ($80 - $BF)
sl2_cs : out std_logic -- Expansion slot 2 ($C0 - $FF)
);
end peripheral_bus;
--================== End of entity ==============================--
 
-------------------------------------------------------------------------------
-- Architecture for peripheral bus interface
-------------------------------------------------------------------------------
 
architecture rtl of peripheral_bus is
 
 
type hold_state_type is ( hold_release_state, hold_request_state );
signal pb_hold_state : hold_state_type := hold_release_state;
signal pb_wru : std_logic; -- upper byte write strobe
signal pb_wrl : std_logic; -- lower byte write strobe
signal pb_rdu : std_logic; -- upper byte read strobe
signal pb_rdl : std_logic; -- lower byte read strobe
signal pb_hold : std_logic := '0'; -- hold peripheral bus access
signal pb_count : std_logic_vector(3 downto 0) := (others=>'0'); -- hold counter
signal pb_wreg : std_logic_vector(7 downto 0) := (others=>'0'); -- lower byte write register
signal pb_rreg : std_logic_vector(7 downto 0) := (others=>'0'); -- lower byte read register
 
begin
 
peripheral_bus_decode : process( addr, cs )
begin
 
ide_cs <= '0';
eth_cs <= '0';
sl1_cs <= '0';
sl2_cs <= '0';
case addr(7 downto 6) is
--
-- IDE Interface $E100 to $E13F
--
when "00" =>
ide_cs <= cs;
--
-- Ethernet Interface $E140 to $E17F
--
when "01" =>
eth_cs <= cs;
--
-- Slot 1 Interface $E180 to $E1BF
--
when "10" =>
sl1_cs <= cs;
--
-- Slot 2 Interface $E1C0 to $E1FF
--
when "11" =>
sl2_cs <= cs;
--
-- Nothing else
--
when others =>
null;
end case;
 
end process;
 
--
-- 16-bit Peripheral Bus
-- 6809 Big endian
-- ISA bus little endian
-- Not sure about IDE interface
--
peripheral_bus_control: process( clk, rst, cs, addr, rw, data_in,
pb_hold, pb_wreg, pb_rreg,
pb_wru, pb_wrl, pb_rdu, pb_rdl, pb_data )
begin
pb_addr <= addr(5 downto 1);
--
-- internal read/write strobes
--
pb_wru <= cs and (not rw) and (not addr(0));
pb_wrl <= cs and (not rw) and addr(0) ;
pb_rdu <= cs and rw and (not addr(0));
pb_rdl <= cs and rw and addr(0) ;
 
pb_wr_n <= not pb_wrl;
pb_rd_n <= not pb_rdu;
 
--
-- The peripheral bus will be an output
-- the registered even byte on data(15 downto 8)
-- and the CPU odd bytes on data(7 downto 0)
-- on odd byte writes
--
if pb_wrl = '1' then
pb_data <= pb_wreg & data_in;
else
pb_data <= (others => 'Z');
end if;
 
--
-- On even byte reads,
-- the CPU reads the low (even) byte of the peripheral bus
-- On odd byte reads,
-- the CPU reads the registered (odd byte) input from the peripheral bus
--
if pb_rdu = '1' then
data_out <= pb_data(15 downto 8);
elsif pb_rdl = '1' then
data_out <= pb_rreg;
else
data_out <= (others => '0');
end if;
--
-- Register upper byte from CPU on first CPU write
-- and lower byte from the peripheral bus on first CPU read
--
if falling_edge(clk) then
if rst = '1' then
pb_wreg <= (others => '0');
pb_rreg <= (others => '0');
else
 
if pb_wru = '1' then
pb_wreg <= data_in;
end if;
 
if pb_rdu = '1' then
pb_rreg <= pb_data(7 downto 0);
end if;
 
end if;
end if;
 
end process;
 
--
-- Hold Peripheral bus accesses for a few cycles
--
peripheral_bus_hold: process( clk, rst, cs,
pb_hold_state, pb_hold,
pb_rdu, pb_wrl )
begin
if rising_edge( clk ) then
if rst = '1' then
pb_hold <= '0';
pb_count <= "0000";
pb_hold_state <= hold_release_state;
else
--
-- The perpheral bus hold signal should be generated on
-- 16 bit bus even upper byte read or
-- 16 bit bus odd lower byte write.
--
case pb_hold_state is
 
when hold_release_state =>
if (pb_rdu = '1') or (pb_wrl = '1') then
pb_count <= "0011";
pb_hold <= '1';
pb_hold_state <= hold_request_state;
else
pb_hold <= '0';
pb_hold_state <= hold_release_state;
end if;
 
when hold_request_state =>
if pb_count = "0000" then
pb_hold <= '0';
pb_hold_state <= hold_release_state;
else
pb_count <= pb_count - "0001";
end if;
 
when others =>
null;
 
end case;
end if;
end if;
hold <= cs and pb_hold;
end process;
 
end rtl;
/priority_rot.vhd
0,0 → 1,82
--===========================================================================--
-- --
-- priority_rot.vhd - Synthesizable Rotating Priority Encoder --
-- --
--===========================================================================--
--
-- File name : priority_rot.vhd
--
-- Purpose : Implements a rotating priority encoder
--
-- Dependencies : ieee.std_logic_1164
-- ieee.std_logic_unsigned
-- ieee.std_logic_arith
-- unisim.vcomponents
--
-- Author : John E. Kent
--
-- Email : dilbert57@opencores.org
--
-- Web : http://opencores.org/project,system09
--
-- Priority_rot.vhd is a rotating priority encoder written in VHDL.
--
-- Copyright (C) 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 30th May 2010 Initial version
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
 
library unisim;
use unisim.vcomponents.all;
 
entity priority_rot is
generic (
WIDTH = 8
)
port (
clk : in std_logic;
rst : in std_logic;
input : in std_logic_vector(WIDTH-1 downto 0);
output : out std_logic_vector(log2(WIDTH)-1 downto 0);
valid : out std_logic
)
);
end priority_rot;
 
architecture rtl of priority_rot is
 
constant OUT_WIDTH : integer := log2(WIDTH);
 
begin
 
for i in 1 to WIDTH loop
j := log2( i );
if( input(i-1) = '1' ) then
 
end loop;
end architecture;
 
/GNU_GENERAL_PUBLIC_LICENSE.doc Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
GNU_GENERAL_PUBLIC_LICENSE.doc Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: dma6844.vhd =================================================================== --- dma6844.vhd (nonexistent) +++ dma6844.vhd (revision 100) @@ -0,0 +1,243 @@ +--===========================================================================-- +-- -- +-- Synthesizable 6844 Compatible DMA Controller -- +-- -- +--===========================================================================-- +-- +-- File name : dma6844.vhd +-- +-- Entity name : dma6844 +-- +-- Purpose : Implements a 6844 compatible Direct Memory Access Controller +-- It is intended for use with 68xx compatible FPGA SoCs. +-- +-- Dependencies : ieee.std_logic_1164 +-- ieee.std_logic_unsigned +-- ieee.std_logic_arith +-- unisim.vcomponents +-- +-- Author : John E. Kent +-- +-- Email : dilbert57@opencores.org +-- +-- Web : http://opencores.org/project,system09 +-- +-- Registers : +-- +-- 4 Channel version +-- +-- IO + 0 = DMA_AH0 = Address Register 0 High +-- IO + 1 = DMA_AL0 = Address Register 0 Low +-- IO + 2 = DMA_CH0 = Count Register 0 High +-- IO + 3 = DMA_CL0 = Count Register 0 Low +-- +-- IO + 4 = DMA_AH1 = Address Register 1 High +-- IO + 5 = DMA_AL1 = Address Register 1 Low +-- IO + 6 = DMA_CH1 = Count Register 1 High +-- IO + 7 = DMA_CL1 = Count Register 1 Low +-- +-- IO + 8 = DMA_AH2 = Address Register 2 High +-- IO + 9 = DMA_AL2 = Address Register 2 Low +-- IO + 10 = DMA_CH2 = Count Register 2 High +-- IO + 11 = DMA_CL2 = Count Register 2 Low +-- +-- IO + 12 = DMA_AH3 = Address Register 3 High +-- IO + 13 = DMA_AL3 = Address Register 3 Low +-- IO + 14 = DMA_CH3 = Count Register 3 High +-- IO + 15 = DMA_CL3 = Count Register 3 Low +-- +-- IO + 16 = DMA_CC0 = Channel Control Register 0 +-- IO + 17 = DMA_CC1 = Channel Control Register 1 +-- IO + 18 = DMA_CC2 = Channel Control Register 2 +-- IO + 19 = DMA_CC3 = Channel Control Register 3 +-- Bit[7] = DMA_DEF = DMA END FLAG (DEND) +-- Bit[6] = DMA_BSY = DMA BUSY FLAG (READ ONLY) +-- Bit[3] = DMA_AUD = DMA ADDRESS NOT UP/DOWN +-- Bit[2] = DMA_MCA = DMA MODE CONTROL 0=>DRQ2 1=>DRQ1 +-- Bit[1] = DMA_MCB = DMA MODE CONTROL 0=>SINGLE 1=>BLOCK +-- 0 0 = DMA_MD2 = DMA MODE 2 - SINGLE TRANSFER - DRQ2 +-- 0 1 = DMA_MD3 = DMA MODE 3 - BLOCK TRANSFER - DRQ2 +-- 1 0 = DMA_MD1 = DMA MODE 1 - SINGLE TRANSFER - DRQ1 +-- 1 1 = DMA_MDU = DMA MODE 4 - BLOCK TRANSFER - DRQ1 - ACTUALLY UDEFINED +-- Bit[0] = DMA_RW = DMA READ/NOT WRITE +-- +-- IO + 20 = DMA_PRI = DMA Priority Control Register +-- Bit[7] = DMA_ROT = DMA Rotate Control 0=>FIXED 1=>ROTATE +-- Bit[3] = DMA_RE3 = DMA REQUEST ENABLE #3 +-- Bit[2] = DMA_RE2 = DMA REQUEST ENABLE #2 +-- Bit[1] = DMA_RE1 = DMA REQUEST ENABLE #1 +-- Bit[0] = DMA_RE0 = DMA REQUEST ENABLE #0 +-- +-- IO + 21 = DMA_INT = DMA Interrupt Control Register +-- Bit[7] = DMA_IEF = DMA END IRQ FLAG +-- Bit[3] = DMA_IE3 = DMA END IRQ ENABLE #3 +-- Bit[2] = DMA_IE2 = DMA END IRQ ENABLE #2 +-- Bit[1] = DMA_IE1 = DMA END IRQ ENABLE #1 +-- Bit[0] = DMA_IE0 = DMA END IRQ ENABLE #0 +-- +-- IO + 22 = DMA_CHN = DMA Data Chain register +-- Bit[3] = DMA_C24 = TWO/FOUR CHANNEL SELECT +-- Bit[2] = DMA_DCB = DATA CHAIN CHANNEL SELECT B +-- Bit[1] = DMA_DCA = DATA CHAIN CHANNEL SELECT A +-- Bit[0] = DMA_DCE = DATA CHAIN ENABLE +-- +-- Copyright (C) 2010 John Kent +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +--===========================================================================-- +-- -- +-- Revision History -- +-- -- +--===========================================================================-- +-- +-- Revision Author Date Description +-- 0.1 John E. Kent 18th April 2010 Initial release +-- + +library ieee; + use ieee.std_logic_1164.all; + use ieee.std_logic_unsigned.all; + use ieee.std_logic_arith.all; + +library unisim; + use unisim.vcomponents.all; + +entity dma6844 is + generic ( + ADDR_WIDTH = 16; + DATA_WIDTH = 8; + CHAN_COUNT = 4 + ) + port ( + -- + -- CPU Slave Interface + -- + clk : in std_logic; + rst : in std_logic; + rw : out std_logic; + cs : out std_logic; + addr : in std_logic_vector(LOG2(CHAN_COUNT*4*ADDR_WIDTH/DATA_WIDTH)-1 downto 0); + data_in : in std_logic_vector(DATA_WIDTH-1 downto 0); + data_out : out std_logic_vector(DATA_WIDTH-1 downto 0); + irq : out std_logic; + -- + -- Bus Master Interface + -- + breq : out std_logic; + bgnt : in std_logic; + brw : out std_logic; + bvma : out std_logic; + baddr : out std_logic_vector(ADDR_WIDTH-1 downto 0); + -- + -- Device Interface + -- + txreq : in std_logic_vector(CHAN_COUNT-1 downto 0); + txstb : out std_logic_vector(CHAN_COUNT-1 downto 0); + txack : out std_logic_vector(CHAN_COUNT-1 downto 0); + txend : out std_logic_vector(CHAN_COUNT-1 downto 0) + ); +end dma6844; + +architecture rtl of dma6844 is + +constant REG_COUNT : integer = (CHAN_COUNT * 2 * ADDR_WIDTH / DATA_WIDTH) + DMA_CHAN + 3; + +subtype addr_subtype is std_logic_vector(ADDR_WIDTH-1 downto 0); +subtype data_subtype is std_logic_vector(DATA_WIDTH-1 downto 0); + +type addr_type is array(0 to CHAN_COUNT-1) of addr_subtype; +type data_type is array(0 to CHAN_COUNT-1) of data_subtype; +type reg_type is array(0 to REG_COUNT-1) of data_subtype; + +signal dma_addr : addr_type; +signal dma_count : addr_type; +signal dma_in_reg : reg_type; +signal dma_out_reg : reg_type; + +signal dma_reg_wr : std_logic := '0'; +signal dma_reg_rd : std_logic := '0'; + +-- +-- Registers +-- +signal dma_adh_reg : data_type; +signal dma_adl_reg : data_type; +signal dma_cth_reg : data_type; +signal dma_ctl_reg : data_type; +signal dma_chc_reg : data_type; +signal dma_pri_reg : std_logic_vector(DATA_WIDTH-1 downto 0); +signal dma_irq_reg : std_logic_vector(DATA_WIDTH-1 downto 0); +signal dma_chn_reg : std_logic_vector(DATA_WIDTH-1 downto 0); + +begin +-- +-- Write to DMA input register +-- +dma_reg_write : process( clk, rst ) +variable reg_addr : integer := 0; +begin + if( falling_edge(clk) ) + if( rst = '1' ) then + for i in 0 to CHAN_COUNT-1 loop + dma_addr(i) <= (others=>'0'); + dma_count(i) <= (others=>'0'); + end loop; + for i in 0 to REG_COUNT-1 loop + dma_in_reg(i) <= (others=>'0'); + end loop; + else + if( cs='1' and rw='0' ) then + reg_addr := conv_integer(addr(ADDR_WIDTH-1 downto 0)); + if( reg_addr < REG_COUNT ) then + dma_in_reg(reg_addr) <= data_in; + end if; + end if; + end if; + end if; +end process; + +-- +-- Assign input register to specific register names +-- +dma_reg_assign : process( dma_in_reg ) +begin + for i in 0 to CHAN_COUNT-1 loop + dma_adh_reg(i) <= dma_in_reg((i*4)+0); + dma_adl_reg(i) <= dma_in_reg((i*4)+1); + dma_cth_reg(i) <= dma_in_reg((i*4)+2); + dma_ctl_reg(i) <= dma_in_reg((i*4)+3); + dma_chc_reg(i) <= dma_in_reg((CHAN_COUNT*4)+i); + end loop; + dma_pri_reg <= dma_in_reg((CHAN_COUNT*5)+0); + dma_irq_reg <= dma_in_reg((CHAN_COUNT*5)+1); + dma_chn_reg <= dma_in_reg((CHAN_COUNT*5)+2); +end process; + +-- +-- Process Transfer Request Inputs +-- +dma_tx_req : process( clk, rst, txreq ) +begin + if( rising_edge( clk ) ) then + if( rst='1' ) then + else + for i in 0 to CHAN_COUNT-1 loop + end loop; + end if; + end if; +end process; + +end architecture rtl; + Index: GNU_GENERAL_PUBLIC_LICENSE.pdf =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: GNU_GENERAL_PUBLIC_LICENSE.pdf =================================================================== --- GNU_GENERAL_PUBLIC_LICENSE.pdf (nonexistent) +++ GNU_GENERAL_PUBLIC_LICENSE.pdf (revision 100)
GNU_GENERAL_PUBLIC_LICENSE.pdf Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: acia6850.vhd =================================================================== --- acia6850.vhd (nonexistent) +++ acia6850.vhd (revision 100) @@ -0,0 +1,897 @@ +--===========================================================================-- +-- -- +-- Synthesizable 6850 compatible ACIA -- +-- -- +--===========================================================================-- +-- +-- File name : acia6850.vhd +-- +-- Entity name : acia6850 +-- +-- Purpose : Implements a RS232 6850 compatible +-- Asynchronous Communications Interface Adapter (ACIA) +-- +-- Dependencies : ieee.std_logic_1164 +-- ieee.numeric_std +-- unisim.vcomponents +-- +-- Author : John E. Kent +-- +-- Email : dilbert57@opencores.org +-- +-- Web : http://opencores.org/project,system09 +-- +-- Origins : miniUART written by Ovidiu Lupas olupas@opencores.org +-- +-- Registers : +-- +-- IO address + 0 Read - Status Register +-- +-- Bit[7] - Interrupt Request Flag +-- Bit[6] - Receive Parity Error (parity bit does not match) +-- Bit[5] - Receive Overrun Error (new character received before last read) +-- Bit[4] - Receive Framing Error (bad stop bit) +-- Bit[3] - Clear To Send level +-- Bit[2] - Data Carrier Detect (lost modem carrier) +-- Bit[1] - Transmit Buffer Empty (ready to accept next transmit character) +-- Bit[0] - Receive Data Ready (character received) +-- +-- IO address + 0 Write - Control Register +-- +-- Bit[7] - Rx Interupt Enable +-- 0 - disabled +-- 1 - enabled +-- Bits[6..5] - Transmit Control +-- 0 0 - TX interrupt disabled, RTS asserted +-- 0 1 - TX interrupt enabled, RTS asserted +-- 1 0 - TX interrupt disabled, RTS cleared +-- 1 1 - TX interrupt disabled, RTS asserted, Send Break +-- Bits[4..2] - Word Control +-- 0 0 0 - 7 data, even parity, 2 stop +-- 0 0 1 - 7 data, odd parity, 2 stop +-- 0 1 0 - 7 data, even parity, 1 stop +-- 0 1 1 - 7 data, odd parity, 1 stop +-- 1 0 0 - 8 data, no parity, 2 stop +-- 1 0 1 - 8 data, no parity, 1 stop +-- 1 1 0 - 8 data, even parity, 1 stop +-- 1 1 1 - 8 data, odd parity, 1 stop +-- Bits[1..0] - Baud Control +-- 0 0 - Baud Clk divide by 1 +-- 0 1 - Baud Clk divide by 16 +-- 1 0 - Baud Clk divide by 64 +-- 1 1 - Reset +-- +-- IO address + 1 Read - Receive Data Register +-- +-- Read when Receive Data Ready bit set +-- Read resets Receive Data Ready bit +-- +-- IO address + 1 Write - Transmit Data Register +-- +-- Write when Transmit Buffer Empty bit set +-- Write resets Transmit Buffer Empty Bit +-- +-- +-- 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 . +-- +--===========================================================================-- +-- -- +-- Revision History -- +-- -- +--===========================================================================-- +-- +-- Version Author Date Changes +-- +-- 0.1 Ovidiu Lupas 2000-01-15 New model +-- 1.0 Ovidiu Lupas 2000-01 Synthesis optimizations +-- 2.0 Ovidiu Lupas 2000-04 Bugs removed - the RSBusCtrl did not +-- process all possible situations +-- +-- 3.0 John Kent 2002-10 Changed Status bits to match MC6805 +-- Added CTS, RTS, Baud rate control & Software Reset +-- 3.1 John Kent 2003-01-05 Added Word Format control a'la mc6850 +-- 3.2 John Kent 2003-07-19 Latched Data input to UART +-- 3.3 John Kent 2004-01-16 Integrated clkunit in rxunit & txunit +-- TX / RX Baud Clock now external +-- also supports x1 clock and DCD. +-- 3.4 John Kent 2005-09-13 Removed LoadCS signal. +-- Fixed ReadCS and Read +-- in miniuart_DCD_Init process +-- 3.5 John Kent 2006-11-28 Cleaned up code. +-- +-- 4.0 John Kent 2007-02-03 Renamed ACIA6850 +-- 4.1 John Kent 2007-02-06 Made software reset synchronous +-- 4.2 John Kent 2007-02-25 Changed sensitivity lists +-- Rearranged Reset process. +-- 4.3 John Kent 2010-06-17 Updated header +-- 4.4 John Kent 2010-08-27 Combined with ACIA_RX & ACIA_TX +-- Renamed to acia6850 +-- + +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + use ieee.std_logic_unsigned.all; +library unisim; + use unisim.vcomponents.all; + +----------------------------------------------------------------------- +-- Entity for ACIA_6850 -- +----------------------------------------------------------------------- + +entity acia6850 is + port ( + -- + -- CPU Interface signals + -- + clk : in std_logic; -- System Clock + rst : in std_logic; -- Reset input (active high) + cs : in std_logic; -- miniUART Chip Select + addr : in std_logic; -- Register Select + rw : in std_logic; -- Read / Not Write + data_in : in std_logic_vector(7 downto 0); -- Data Bus In + data_out : out std_logic_vector(7 downto 0); -- Data Bus Out + irq : out std_logic; -- Interrupt Request out + -- + -- RS232 Interface Signals + -- + RxC : in std_logic; -- Receive Baud Clock + TxC : in std_logic; -- Transmit Baud Clock + RxD : in std_logic; -- Receive Data + TxD : out std_logic; -- Transmit Data + DCD_n : in std_logic; -- Data Carrier Detect + CTS_n : in std_logic; -- Clear To Send + RTS_n : out std_logic -- Request To send + ); +end acia6850; --================== End of entity ==============================-- + +------------------------------------------------------------------------------- +-- Architecture for ACIA_6850 Interface registees +------------------------------------------------------------------------------- + +architecture rtl of acia6850 is + + type DCD_State_Type is (DCD_State_Idle, DCD_State_Int, DCD_State_Reset); + + ----------------------------------------------------------------------------- + -- Signals + ----------------------------------------------------------------------------- + -- + -- Reset signals + -- + signal ac_rst : std_logic; -- Reset (Software & Hardware) + signal rx_rst : std_logic; -- Receive Reset (Software & Hardware) + signal tx_rst : std_logic; -- Transmit Reset (Software & Hardware) + + -------------------------------------------------------------------- + -- Status Register: StatReg + ---------------------------------------------------------------------- + -- + -- IO address + 0 Read + -- + -----------+--------+-------+--------+--------+--------+--------+--------+ + -- Irq | PErr | OErr | FErr | CTS | DCD | TxRdy | RxRdy | + -----------+--------+-------+--------+--------+--------+--------+--------+ + -- + -- Irq - Bit[7] - Interrupt request + -- PErr - Bit[6] - Receive Parity error (parity bit does not match) + -- OErr - Bit[5] - Receive Overrun error (new character received before last read) + -- FErr - Bit[4] - Receive Framing Error (bad stop bit) + -- CTS - Bit[3] - Clear To Send level + -- DCD - Bit[2] - Data Carrier Detect (lost modem carrier) + -- TxRdy - Bit[1] - Transmit Buffer Empty (ready to accept next transmit character) + -- RxRdy - Bit[0] - Receive Data Ready (character received) + -- + + signal StatReg : std_logic_vector(7 downto 0) := (others => '0'); -- status register + + ---------------------------------------------------------------------- + -- Control Register: CtrlReg + ---------------------------------------------------------------------- + -- + -- IO address + 0 Write + -- + -----------+--------+--------+--------+--------+--------+--------+--------+ + -- RxIE |TxCtl(1)|TxCtl(0)|WdFmt(2)|WdFmt(1)|WdFmt(0)|BdCtl(1)|BdCtl(0)| + -----------+--------+--------+--------+--------+--------+--------+--------+ + -- RxIEnb - Bit[7] + -- 0 - Rx Interrupt disabled + -- 1 - Rx Interrupt enabled + -- TxCtl - Bits[6..5] + -- 0 1 - Tx Interrupt Enable + -- 1 0 - RTS high + -- WdFmt - Bits[4..2] + -- 0 0 0 - 7 data, even parity, 2 stop + -- 0 0 1 - 7 data, odd parity, 2 stop + -- 0 1 0 - 7 data, even parity, 1 stop + -- 0 1 1 - 7 data, odd parity, 1 stop + -- 1 0 0 - 8 data, no parity, 2 stop + -- 1 0 1 - 8 data, no parity, 1 stop + -- 1 1 0 - 8 data, even parity, 1 stop + -- 1 1 1 - 8 data, odd parity, 1 stop + -- BdCtl - Bits[1..0] + -- 0 0 - Baud Clk divide by 1 + -- 0 1 - Baud Clk divide by 16 + -- 1 0 - Baud Clk divide by 64 + -- 1 1 - reset + signal CtrlReg : std_logic_vector(7 downto 0) := (others => '0'); -- control register + + ---------------------------------------------------------------------- + -- Receive Register + ---------------------------------------------------------------------- + -- + -- IO address + 1 Read + -- + signal RxReg : std_logic_vector(7 downto 0) := (others => '0'); + + ---------------------------------------------------------------------- + -- Transmit Register + ---------------------------------------------------------------------- + -- + -- IO address + 1 Write + -- + signal TxReg : std_logic_vector(7 downto 0) := (others => '0'); + + signal TxDat : std_logic := '1'; -- Transmit data bit + signal TxRdy : std_logic := '0'; -- Transmit buffer empty + signal RxRdy : std_logic := '0'; -- Receive Data ready + -- + signal FErr : std_logic := '0'; -- Frame error + signal OErr : std_logic := '0'; -- Output error + signal PErr : std_logic := '0'; -- Parity Error + -- + signal TxIE : std_logic := '0'; -- Transmit interrupt enable + signal RxIE : std_logic := '0'; -- Receive interrupt enable + -- + signal RxRd : std_logic := '0'; -- Read receive buffer + signal TxWr : std_logic := '0'; -- Write Transmit buffer + signal StRd : std_logic := '0'; -- Read status register + -- + signal DCDState : DCD_State_Type; -- DCD Reset state sequencer + signal DCDDel : std_logic := '0'; -- Delayed DCD_n + signal DCDEdge : std_logic := '0'; -- Rising DCD_N Edge Pulse + signal DCDInt : std_logic := '0'; -- DCD Interrupt + + signal BdFmt : std_logic_vector(1 downto 0) := "00"; -- Baud Clock Format + signal WdFmt : std_logic_vector(2 downto 0) := "000"; -- Data Word Format + + ----------------------------------------------------------------------------- + -- RX Signals + ----------------------------------------------------------------------------- + + type RxStateType is ( RxState_Wait, RxState_Data, RxState_Parity, RxState_Stop ); + + signal RxState : RxStateType; -- receive bit state + + signal RxDatDel0 : Std_Logic := '0'; -- Delayed Rx Data + signal RxDatDel1 : Std_Logic := '0'; -- Delayed Rx Data + signal RxDatDel2 : Std_Logic := '0'; -- Delayed Rx Data + signal RxDatEdge : Std_Logic := '0'; -- Rx Data Edge pulse + + signal RxClkDel : Std_Logic := '0'; -- Delayed Rx Input Clock + signal RxClkEdge : Std_Logic := '0'; -- Rx Input Clock Edge pulse + signal RxStart : Std_Logic := '0'; -- Rx Start request + signal RxEnable : Std_Logic := '0'; -- Rx Enabled + signal RxClkCnt : Std_Logic_Vector(5 downto 0) := (others => '0'); -- Rx Baud Clock Counter + signal RxBdClk : Std_Logic := '0'; -- Rx Baud Clock + signal RxBdDel : Std_Logic := '0'; -- Delayed Rx Baud Clock + + signal RxReq : Std_Logic := '0'; -- Rx Data Valid + signal RxAck : Std_Logic := '0'; -- Rx Data Valid + signal RxParity : Std_Logic := '0'; -- Calculated RX parity bit + signal RxBitCount : Std_Logic_Vector(2 downto 0) := (others => '0'); -- Rx Bit counter + signal RxShiftReg : Std_Logic_Vector(7 downto 0) := (others => '0'); -- Shift Register + + ----------------------------------------------------------------------------- + -- TX Signals + ----------------------------------------------------------------------------- + type TxStateType is ( TxState_Idle, TxState_Start, TxState_Data, TxState_Parity, TxState_Stop ); + + signal TxState : TxStateType; -- Transmitter state + + signal TxClkDel : Std_Logic := '0'; -- Delayed Tx Input Clock + signal TxClkEdge : Std_Logic := '0'; -- Tx Input Clock Edge pulse + signal TxClkCnt : Std_Logic_Vector(5 downto 0) := (others => '0'); -- Tx Baud Clock Counter + signal TxBdClk : Std_Logic := '0'; -- Tx Baud Clock + signal TxBdDel : Std_Logic := '0'; -- Delayed Tx Baud Clock + + signal TxReq : std_logic := '0'; -- Request transmit start + signal TxAck : std_logic := '0'; -- Acknowledge transmit start + signal TxParity : Std_logic := '0'; -- Parity Bit + signal TxBitCount : Std_Logic_Vector(2 downto 0) := (others => '0'); -- Data Bit Counter + signal TxShiftReg : Std_Logic_Vector(7 downto 0) := (others => '0'); -- Transmit shift register + +begin + +--------------------------------------------------------------- +-- ACIA Reset may be hardware or software +--------------------------------------------------------------- + acia_reset : process( clk, rst, ac_rst, dcd_n ) + begin + -- + -- ACIA reset Synchronous + -- Includes software reset + -- + if falling_edge(clk) then + ac_rst <= (CtrlReg(1) and CtrlReg(0)) or rst; + end if; + -- Receiver reset + rx_rst <= ac_rst or DCD_n; + -- Transmitter reset + tx_rst <= ac_rst; + + end process; + + +----------------------------------------------------------------------------- +-- Generate Read / Write strobes. +----------------------------------------------------------------------------- + + ACIA_Read_Write : process(clk, ac_rst) + begin + if falling_edge(clk) then + if ac_rst = '1' then + CtrlReg <= (others => '0'); + TxReg <= (others => '0'); + RxRd <= '0'; + TxWr <= '0'; + StRd <= '0'; + else + RxRd <= '0'; + TxWr <= '0'; + StRd <= '0'; + if cs = '1' then + if Addr = '0' then -- Control / Status register + if rw = '0' then -- write control register + CtrlReg <= data_in; + else -- read status register + StRd <= '1'; + end if; + else -- Data Register + if rw = '0' then -- write transmiter register + TxReg <= data_in; + TxWr <= '1'; + else -- read receiver register + RxRd <= '1'; + end if; + end if; + end if; + end if; + end if; + end process; + + ----------------------------------------------------------------------------- + -- ACIA Status Register + ----------------------------------------------------------------------------- + + acia_status : process( clk ) + begin + if falling_edge( clk ) then + StatReg(0) <= RxRdy; -- Receive Data Ready + StatReg(1) <= TxRdy and (not CTS_n); -- Transmit Buffer Empty + StatReg(2) <= DCDInt; -- Data Carrier Detect + StatReg(3) <= CTS_n; -- Clear To Send + StatReg(4) <= FErr; -- Framing error + StatReg(5) <= OErr; -- Overrun error + StatReg(6) <= PErr; -- Parity error + StatReg(7) <= (RxIE and RxRdy) or + (RxIE and DCDInt) or + (TxIE and TxRdy); + end if; + end process; + + +----------------------------------------------------------------------------- +-- ACIA Transmit Control +----------------------------------------------------------------------------- + + acia_control : process(CtrlReg, TxDat) + begin + case CtrlReg(6 downto 5) is + when "00" => -- Disable TX Interrupts, Assert RTS + TxD <= TxDat; + TxIE <= '0'; + RTS_n <= '0'; + when "01" => -- Enable TX interrupts, Assert RTS + TxD <= TxDat; + TxIE <= '1'; + RTS_n <= '0'; + when "10" => -- Disable Tx Interrupts, Clear RTS + TxD <= TxDat; + TxIE <= '0'; + RTS_n <= '1'; + when "11" => -- Disable Tx interrupts, Assert RTS, send break + TxD <= '0'; + TxIE <= '0'; + RTS_n <= '0'; + when others => + null; + end case; + + RxIE <= CtrlReg(7); + WdFmt <= CtrlReg(4 downto 2); + BdFmt <= CtrlReg(1 downto 0); + end process; + +--------------------------------------------------------------- +-- Set Data Output Multiplexer +-------------------------------------------------------------- + + acia_data_mux : process(Addr, RxReg, StatReg) + begin + if Addr = '1' then + data_out <= RxReg; -- read receiver register + else + data_out <= StatReg; -- read status register + end if; + end process; + + irq <= StatReg(7); + +--------------------------------------------------------------- +-- Data Carrier Detect Edge rising edge detect +--------------------------------------------------------------- + acia_dcd_edge : process( clk, ac_rst ) + begin + if falling_edge(clk) then + if ac_rst = '1' then + DCDDel <= '0'; + DCDEdge <= '0'; + else + DCDDel <= DCD_n; + DCDEdge <= DCD_n and (not DCDDel); + end if; + end if; + end process; + + +--------------------------------------------------------------- +-- Data Carrier Detect Interrupt +--------------------------------------------------------------- +-- If Data Carrier is lost, an interrupt is generated +-- To clear the interrupt, first read the status register +-- then read the data receive register + + acia_dcd_int : process( clk, ac_rst ) + begin + if falling_edge(clk) then + if ac_rst = '1' then + DCDInt <= '0'; + DCDState <= DCD_State_Idle; + else + case DCDState is + when DCD_State_Idle => + -- DCD Edge activates interrupt + if DCDEdge = '1' then + DCDInt <= '1'; + DCDState <= DCD_State_Int; + end if; + when DCD_State_Int => + -- To reset DCD interrupt, + -- First read status + if StRd = '1' then + DCDState <= DCD_State_Reset; + end if; + when DCD_State_Reset => + -- Then read receive register + if RxRd = '1' then + DCDInt <= '0'; + DCDState <= DCD_State_Idle; + end if; + when others => + null; + end case; + end if; + end if; + end process; + + + --------------------------------------------------------------------- + -- Receiver Clock Edge Detection + --------------------------------------------------------------------- + -- A rising edge will produce a one clock cycle pulse + -- + acia_rx_clock_edge : process( clk, rx_rst ) + begin + if falling_edge(clk) then + if rx_rst = '1' then + RxClkDel <= '0'; + RxClkEdge <= '0'; + else + RxClkDel <= RxC; + RxClkEdge <= (not RxClkDel) and RxC; + end if; + end if; + end process; + + --------------------------------------------------------------------- + -- Receiver Data Edge Detection + --------------------------------------------------------------------- + -- A falling edge will produce a pulse on RxClk wide + -- + acia_rx_data_edge : process( clk, rx_rst ) + begin + if falling_edge(clk) then + if rx_rst = '1' then + RxDatDel0 <= '0'; + RxDatDel1 <= '0'; + RxDatDel2 <= '0'; + RxDatEdge <= '0'; + else + RxDatDel0 <= RxD; + RxDatDel1 <= RxDatDel0; + RxDatDel2 <= RxDatDel1; + RxDatEdge <= RxDatDel0 and (not RxD); + end if; + end if; + end process; + + --------------------------------------------------------------------- + -- Receiver Start / Stop + --------------------------------------------------------------------- + -- Enable the receive clock on detection of a start bit + -- Disable the receive clock after a byte is received. + -- + acia_rx_start_stop : process( clk, rx_rst ) + begin + if falling_edge(clk) then + if rx_rst = '1' then + RxEnable <= '0'; + RxStart <= '0'; + elsif (RxEnable = '0') and (RxDatEdge = '1') then + -- Data Edge detected + RxStart <= '1'; -- Request Start and + RxEnable <= '1'; -- Enable Receive Clock + elsif (RxStart = '1') and (RxAck = '1') then + -- Data is being received + RxStart <= '0'; -- Reset Start Request + elsif (RxStart = '0') and (RxAck = '0') then + -- Data has now been received + RxEnable <= '0'; -- Disable Receiver until next Start Bit + end if; + end if; + end process; + + --------------------------------------------------------------------- + -- Receiver Clock Divider + --------------------------------------------------------------------- + -- Hold the Rx Clock divider in reset when the receiver is disabled + -- Advance the count only on a rising Rx clock edge + -- + acia_rx_clock_divide : process( clk, rx_rst ) + begin + if falling_edge(clk) then + if rx_rst = '1' then + RxClkCnt <= (others => '0'); + elsif RxDatEdge = '1' then + -- reset on falling data edge + RxClkCnt <= (others => '0'); + elsif RxClkEdge = '1' then + -- increment count on Clock edge + RxClkCnt <= RxClkCnt + "000001"; + end if; + end if; + end process; + + --------------------------------------------------------------------- + -- Receiver Baud Clock Selector + --------------------------------------------------------------------- + -- BdFmt + -- 0 0 - Baud Clk divide by 1 + -- 0 1 - Baud Clk divide by 16 + -- 1 0 - Baud Clk divide by 64 + -- 1 1 - Reset + -- + acia_rx_baud_clock_select : process( BdFmt, RxC, RxClkCnt ) + begin + case BdFmt is + when "00" => -- Div by 1 + RxBdClk <= RxC; + when "01" => -- Div by 16 + RxBdClk <= RxClkCnt(3); + when "10" => -- Div by 64 + RxBdClk <= RxClkCnt(5); + when others => -- Software Reset + RxBdClk <= '0'; + end case; + end process; + + --------------------------------------------------------------------- + -- Receiver process + --------------------------------------------------------------------- + -- WdFmt - Bits[4..2] + -- 0 0 0 - 7 data, even parity, 2 stop + -- 0 0 1 - 7 data, odd parity, 2 stop + -- 0 1 0 - 7 data, even parity, 1 stop + -- 0 1 1 - 7 data, odd parity, 1 stop + -- 1 0 0 - 8 data, no parity, 2 stop + -- 1 0 1 - 8 data, no parity, 1 stop + -- 1 1 0 - 8 data, even parity, 1 stop + -- 1 1 1 - 8 data, odd parity, 1 stop + acia_rx_receive : process( clk, rst ) + begin + if falling_edge( clk ) then + if rx_rst = '1' then + FErr <= '0'; + OErr <= '0'; + PErr <= '0'; + RxShiftReg <= (others => '0'); -- Reset Shift register + RxReg <= (others => '0'); + RxParity <= '0'; -- reset Parity bit + RxAck <= '0'; -- Receiving data + RxBitCount <= (others => '0'); + RxState <= RxState_Wait; + else + RxBdDel <= RxBdClk; + if RxBdDel = '0' and RxBdClk = '1' then + case RxState is + when RxState_Wait => + RxShiftReg <= (others => '0'); -- Reset Shift register + RxParity <= '0'; -- Reset Parity bit + if WdFmt(2) = '0' then -- WdFmt(2) = '0' => 7 data bits + RxBitCount <= "110"; + else -- WdFmt(2) = '1' => 8 data bits + RxBitCount <= "111"; + end if; + if RxDatDel2 = '0' then -- look for start bit + RxState <= RxState_Data; -- if low, start reading data + end if; + + when RxState_Data => -- Receiving data bits + RxShiftReg <= RxDatDel2 & RxShiftReg(7 downto 1); + RxParity <= RxParity xor RxDatDel2; + RxAck <= '1'; -- Flag receive in progress + RxBitCount <= RxBitCount - "001"; + if RxBitCount = "000" then + if WdFmt(2) = '0' then -- WdFmt(2) = '0' => 7 data + RxState <= RxState_Parity; -- 7 bits always has parity + elsif WdFmt(1) = '0' then -- WdFmt(2) = '1' => 8 data + RxState <= RxState_Stop; -- WdFmt(1) = '0' => no parity + PErr <= '0'; -- Reset Parity Error + else + RxState <= RxState_Parity; -- WdFmt(1) = '1' => 8 data + parity + end if; + end if; + + when RxState_Parity => -- Receive Parity bit + if WdFmt(2) = '0' then -- if 7 data bits, shift parity into MSB + RxShiftReg <= RxDatDel2 & RxShiftReg(7 downto 1); -- 7 data + parity + end if; + if RxParity = (RxDatDel2 xor WdFmt(0)) then + PErr <= '1'; -- If parity not the same flag error + else + PErr <= '0'; + end if; + RxState <= RxState_Stop; + + when RxState_Stop => -- stop bit (Only one required for RX) + RxAck <= '0'; -- Flag Receive Complete + RxReg <= RxShiftReg; + if RxDatDel2 = '1' then -- stop bit expected + FErr <= '0'; -- yes, no framing error + else + FErr <= '1'; -- no, framing error + end if; + if RxRdy = '1' then -- Has previous data been read ? + OErr <= '1'; -- no, overrun error + else + OErr <= '0'; -- yes, no over run error + end if; + RxState <= RxState_Wait; + + when others => + RxAck <= '0'; -- Flag Receive Complete + RxState <= RxState_Wait; + end case; + end if; + end if; + end if; + + end process; + + --------------------------------------------------------------------- + -- Receiver Read process + --------------------------------------------------------------------- + acia_rx_read : process( clk, rst, RxRdy ) + begin + if falling_edge(clk) then + if rx_rst = '1' then + RxRdy <= '0'; + RxReq <= '0'; + elsif RxRd = '1' then + -- Data was read, + RxRdy <= '0'; -- Reset receive full + RxReq <= '1'; -- Request more data + elsif RxReq = '1' and RxAck = '1' then + -- Data is being received + RxReq <= '0'; -- reset receive request + elsif RxReq = '0' and RxAck = '0' then + -- Data now received + RxRdy <= '1'; -- Flag RxRdy and read Shift Register + end if; + end if; + end process; + + + --------------------------------------------------------------------- + -- Transmit Clock Edge Detection + -- A falling edge will produce a one clock cycle pulse + --------------------------------------------------------------------- + + acia_tx_clock_edge : process( Clk, tx_rst ) + begin + if falling_edge(clk) then + if tx_rst = '1' then + TxClkDel <= '0'; + TxClkEdge <= '0'; + else + TxClkDel <= TxC; + TxClkEdge <= TxClkDel and (not TxC); + end if; + end if; + end process; + + --------------------------------------------------------------------- + -- Transmit Clock Divider + -- Advance the count only on an input clock pulse + --------------------------------------------------------------------- + + acia_tx_clock_divide : process( clk, tx_rst ) + begin + if falling_edge(clk) then + if tx_rst = '1' then + TxClkCnt <= (others=>'0'); + elsif TxClkEdge = '1' then + TxClkCnt <= TxClkCnt + "000001"; + end if; + end if; + end process; + + --------------------------------------------------------------------- + -- Transmit Baud Clock Selector + --------------------------------------------------------------------- + acia_tx_baud_clock_select : process( BdFmt, TxClkCnt, TxC ) + begin + -- BdFmt + -- 0 0 - Baud Clk divide by 1 + -- 0 1 - Baud Clk divide by 16 + -- 1 0 - Baud Clk divide by 64 + -- 1 1 - reset + case BdFmt is + when "00" => -- Div by 1 + TxBdClk <= TxC; + when "01" => -- Div by 16 + TxBdClk <= TxClkCnt(3); + when "10" => -- Div by 64 + TxBdClk <= TxClkCnt(5); + when others => -- Software reset + TxBdClk <= '0'; + end case; + end process; + + ----------------------------------------------------------------------------- + -- Implements the Tx unit + ----------------------------------------------------------------------------- + -- WdFmt - Bits[4..2] + -- 0 0 0 - 7 data, even parity, 2 stop + -- 0 0 1 - 7 data, odd parity, 2 stop + -- 0 1 0 - 7 data, even parity, 1 stop + -- 0 1 1 - 7 data, odd parity, 1 stop + -- 1 0 0 - 8 data, no parity, 2 stop + -- 1 0 1 - 8 data, no parity, 1 stop + -- 1 1 0 - 8 data, even parity, 1 stop + -- 1 1 1 - 8 data, odd parity, 1 stop + acia_tx_transmit : process( clk, tx_rst) + begin + if falling_edge(clk) then + if tx_rst = '1' then + TxDat <= '1'; + TxShiftReg <= (others=>'0'); + TxParity <= '0'; + TxBitCount <= (others=>'0'); + TxAck <= '0'; + TxState <= TxState_Idle; + else + + TxBdDel <= TxBdClk; + -- On rising edge of baud clock, run the state machine + if TxBdDel = '0' and TxBdClk = '1' then + + case TxState is + when TxState_Idle => + TxDat <= '1'; + if TxReq = '1' then + TxShiftReg <= TxReg; -- Load Shift reg with Tx Data + TxAck <= '1'; + TxState <= TxState_Start; + end if; + + when TxState_Start => + TxDat <= '0'; -- Start bit + TxParity <= '0'; + if WdFmt(2) = '0' then + TxBitCount <= "110"; -- 7 data + parity + else + TxBitCount <= "111"; -- 8 data + end if; + TxState <= TxState_Data; + + when TxState_Data => + TxDat <= TxShiftReg(0); + TxShiftReg <= '1' & TxShiftReg(7 downto 1); + TxParity <= TxParity xor TxShiftReg(0); + TxBitCount <= TxBitCount - "001"; + if TxBitCount = "000" then + if (WdFmt(2) = '1') and (WdFmt(1) = '0') then + if WdFmt(0) = '0' then -- 8 data bits + TxState <= TxState_Stop; -- 2 stops + else + TxAck <= '0'; + TxState <= TxState_Idle; -- 1 stop + end if; + else + TxState <= TxState_Parity; -- parity + end if; + end if; + + when TxState_Parity => -- 7/8 data + parity bit + if WdFmt(0) = '0' then + TxDat <= not(TxParity); -- even parity + else + TxDat <= TxParity; -- odd parity + end if; + if WdFmt(1) = '0' then + TxState <= TxState_Stop; -- 2 stops + else + TxAck <= '0'; + TxState <= TxState_Idle; -- 1 stop + end if; + + when TxState_Stop => -- first of two stop bits + TxDat <= '1'; + TxAck <= '0'; + TxState <= TxState_Idle; + + end case; + end if; + end if; + end if; + end process; + + --------------------------------------------------------------------- + -- Transmitter Write process + --------------------------------------------------------------------- + + acia_tx_write : process( clk, tx_rst, TxWr, TxReq, TxAck ) + begin + if falling_edge(clk) then + if tx_rst = '1' then + TxRdy <= '0'; + TxReq <= '0'; + elsif TxWr = '1' then + -- Data was read, + TxRdy <= '0'; -- Reset transmit empty + TxReq <= '1'; -- Request data transmit + elsif TxReq = '1' and TxAck = '1' then -- Data is being transmitted + TxReq <= '0'; -- reset transmit request + elsif TxReq = '0' and TxAck = '0' then -- Data transmitted + TxRdy <= '1'; -- Flag TxRdy + end if; + end if; + end process; + +end rtl; + Index: Flasher.vhd =================================================================== --- Flasher.vhd (nonexistent) +++ Flasher.vhd (revision 100) @@ -0,0 +1,99 @@ +--===========================================================================-- +-- -- +-- LED Flasher -- +-- -- +--===========================================================================-- +-- +-- File name : flasher.vhd +-- +-- Entity name : flasher +-- +-- Purpose : Implements a long counter used to flash a LED +-- to indicate code has loaded correctly +-- +-- Dependencies : ieee.std_logic_1164 +-- ieee.numeric_std +-- ieee.std_logic_unsigned +-- unisim.vcomponents +-- +-- Author : John E. Kent +-- +-- Email : dilbert57@opencores.org +-- +-- Web : http://opencores.org/project,system09 +-- +-- +-- Copyright (C) 2010 John Kent +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +--===========================================================================-- +-- -- +-- Revision History -- +-- -- +--===========================================================================-- +-- +-- Version Author Date Changes +-- +-- 0.1 John Kent 2010-08-28 Made separate module +-- + +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + use ieee.std_logic_unsigned.all; +library unisim; + use unisim.vcomponents.all; + +----------------------------------------------------------------------- +-- Entity for B3_SRAM -- +----------------------------------------------------------------------- + +entity flasher is + port ( + clk : in std_logic; -- Clock input + rst : in std_logic; -- Reset input (active high) + LED : out Std_Logic -- LED output + ); +end flasher; + +--================== End of entity ==============================-- + +------------------------------------------------------------------------------- +-- Architecture for Flasher +------------------------------------------------------------------------------- + +architecture rtl of flasher is + +-- Flashing LED test signals +signal countL : std_logic_vector(23 downto 0); + +begin + +-- +-- LED Flasher to indicate code has loaded +-- +my_LED_Flasher : process (clk, rst, CountL ) +begin + if falling_edge(clk) then + if rst = '1' then + countL <= (others=>'0'); + else + countL <= countL + 1; + end if; + end if; + LED <= countL(23); +end process; + +end rtl; \ No newline at end of file Index: twi-master.vhd =================================================================== --- twi-master.vhd (nonexistent) +++ twi-master.vhd (revision 100) @@ -0,0 +1,399 @@ +--===========================================================================-- +-- +-- SYNTHEZIABLE VHDL TWO WIRE INTERFACE +-- +--=========================================================================== +-- +-- This core adheres to the GNU public license +-- +-- Design units : TWI Master core +-- +-- File name : twi.vhd +-- +-- Purpose : Implements an I2C master Interface +-- +-- Dependencies : ieee.std_logic_1164 +-- ieee.numeric_std +-- unisim.vcomponents +-- +-- Revision list : +-- +-- Version Author Date Changes +-- +-- 0.1 John Kent 2010-05-04 New model +-- +-- dilbert57@opencores.org +-- +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +library unisim; + use unisim.vcomponents.all; + +----------------------------------------------------------------------- +-- Entity for TWI -- +----------------------------------------------------------------------- + +entity twi is + generic ( + CLK_FREQ : integer := 25_000_000; + ); + + port ( + -- + -- CPU signals + -- + clk : in std_logic; -- System Clock + rst : in std_logic; -- Reset input (active high) + cs : in std_logic; -- Chip Select + rw : in std_logic; -- Read / Not Write + irq : out std_logic; -- Interrupt + addr : in std_logic; -- Register Select + data_in : in std_logic_vector(7 downto 0); -- Data Bus In + data_out : out std_logic_vector(7 downto 0); -- Data Bus Out + + -- I2C Signals + -- + scl : inout std_logic; -- serial clock + sda : inout std_logic -- serial data + ); +end twi; + +------------------------------------------------------------------------------- +-- Architecture for Two Wire Interface registers +------------------------------------------------------------------------------- + +architecture rtl of twi is + + ----------------------------------------------------------------------------- + -- Signals + ----------------------------------------------------------------------------- + + ---------------------------------------------------------------------- + -- Status Register: twi_status_reg + ---------------------------------------------------------------------- + -- + -- IO address + 0 Read + -- + --+-------+-------+-------+-------+-------+-------+-------+-------+ + --| RXIRQ | TXIRQ | ACKE | | | | TXRDY | RXRDY | + --+-------+-------+-------+-------+-------+-------+-------+-------+ + -- RXIRQ - Bit[7] - Receive Interrupt Request + -- TXIRQ - Bit[6] - Transmit Interrupt Request + -- ACKE - Bit[5] - Acknowledge Error + -- TXRDY - Bit[1] - Transmit Ready (byte transmitted) + -- RXRDY - Bit[0] - Receive Ready (byte received) + -- + signal twi_status_reg : std_logic_vector(7 downto 0) := (others => '0'); + + ---------------------------------------------------------------------- + -- Control Register: twi_control_reg + ---------------------------------------------------------------------- + -- + -- IO address + 0 Write + -- + --+--------+-------+--------+--------+--------+--------+--------+--------+ + --| RXIE | TXIE | TWPS(1)| TWPS(0)| TWBR(3)| TWBR(2)| TWBR(1)| TWBR(0)| + --+--------+-------+--------+--------+--------+--------+--------+--------+ + -- RXIE - Bit[7] + -- 0 - Rx Interrupt disabled + -- 1 - Rx Interrupt enabled + -- TXIE - Bit[6] + -- 0 - Tx Interrupt disabled + -- 1 - Tx Interrupt enabled + -- + -- SCL frequency = CPU Clock Frequency / ( 16 + 2(TWBR) . 4^TWPS) + -- + -- TWPS - Bits[5..4] + -- 0 0 - Prescale by 1 + -- 0 1 - Prescale by 4 + -- 1 0 - Prescale by 16 + -- 1 1 - Prescale by 64 + -- + -- TWBR - Bits[3..0] + -- 0 0 0 0 - Baud Clk divide by 1 + -- 0 0 0 1 - Baud Clk divide by 2 + -- 0 0 1 0 - Baud Clk divide by 3 + -- 0 0 1 1 - Baud Clk divide by 4 + -- 0 1 0 0 - Baud Clk divide by 5 + -- 0 1 0 1 - Baud Clk divide by 6 + -- 0 1 1 0 - Baud Clk divide by 7 + -- 0 1 1 1 - Baud Clk divide by 8 + -- 1 0 0 0 - Baud Clk divide by 9 + -- 1 0 0 1 - Baud Clk divide by 10 + -- 1 0 1 0 - Baud Clk divide by 11 + -- 1 0 1 1 - Baud Clk divide by 12 + -- 1 1 0 0 - Baud Clk divide by 13 + -- 1 1 0 1 - Baud Clk divide by 14 + -- 1 1 1 0 - Baud Clk divide by 15 + -- 1 1 1 1 - Baud Clk divide by 16 + + + signal twi_control_reg : std_logic_vector(7 downto 0) := (others => '0'); -- control register + + ---------------------------------------------------------------------- + -- Receive Register + ---------------------------------------------------------------------- + -- + -- IO address + 1 Read + -- + signal twi_rx_reg : std_logic_vector(7 downto 0) := (others => '0'); + + ---------------------------------------------------------------------- + -- Transmit Register + ---------------------------------------------------------------------- + -- + -- IO address + 1 Write + -- + signal twi_tx_reg : std_logic_vector(7 downto 0) := (others => '0'); + + signal Reset : std_logic; -- Reset (Software & Hardware) + signal RxRst : std_logic; -- Receive Reset (Software & Hardware) + signal TxRst : std_logic; -- Transmit Reset (Software & Hardware) + signal TxDbit : std_logic; -- Transmit data bit + signal RxDR : std_logic := '0'; -- Receive Data ready + signal TxIdle : std_logic; -- Transmitter idle + signal TxBE : std_logic := '0'; -- Transmit buffer empty + signal TxAck : std_logic; -- Byte transmitted to transmitter + -- + signal FErr : std_logic := '0'; -- Frame error + signal OErr : std_logic := '0'; -- Output error + signal PErr : std_logic := '0'; -- Parity Error + -- + signal TxIEnb : std_logic := '0'; -- Transmit interrupt enable + signal RxIEnb : std_logic := '0'; -- Receive interrupt enable + -- + signal ReadRR : std_logic := '0'; -- Read receive buffer + signal WriteTR : std_logic := '0'; -- Write transmit buffer + signal ReadSR : std_logic := '0'; -- Read Status register + -- + signal DCDState : DCD_State_Type; -- DCD Reset state sequencer + signal DCDDel : std_logic := '0'; -- Delayed DCD_n + signal DCDEdge : std_logic := '0'; -- Rising DCD_N Edge Pulse + signal DCDInt : std_logic := '0'; -- DCD Interrupt + +begin + ----------------------------------------------------------------------------- + -- Instantiation of internal components + ----------------------------------------------------------------------------- + + RxDev : entity ACIA_RX port map ( + Clk => clk, + RxRst => RxRst, + RxRd => ReadRR, + WdFmt => CtrlReg(4 downto 2), + BdFmt => CtrlReg(1 downto 0), + RxClk => RxC, + RxDat => RxD, + RxFErr => FErr, + RxOErr => OErr, + RxPErr => PErr, + RxRdy => RxDR, + RxDout => RecvReg + ); + + TxDev : entity ACIA_TX port map ( + Clk => clk, + Reset => TxRst, + Wr => WriteTR, + Din => TxReg, + WdFmt => CtrlReg(4 downto 2), + BdFmt => CtrlReg(1 downto 0), + TxClk => TxC, + Dat => TxDbit, + Empty => TxIdle + ); + +--------------------------------------------------------------- +-- ACIA Reset may be hardware or software +--------------------------------------------------------------- + ACIA_Reset : process(clk, rst) + begin + -- Asynchronous External reset + if rst = '1' then + Reset <= '1'; + elsif falling_edge(clk) then + -- Synchronous Software reset + Reset <= CtrlReg(1) and CtrlReg(0); + end if; + + end process; + + -- Transmitter reset + TxRst <= Reset; + -- Receiver reset + RxRst <= Reset or DCD_n; + + ----------------------------------------------------------------------------- + -- ACIA Status Register + ----------------------------------------------------------------------------- + + ACIA_Status : process(Reset, clk) + begin + if Reset = '1' then + StatReg <= (others => '0'); + elsif falling_edge(clk) then + StatReg(0) <= RxDR; -- Receive Data Ready + StatReg(1) <= TxBE and (not CTS_n); -- Transmit Buffer Empty + StatReg(2) <= DCDInt; -- Data Carrier Detect + StatReg(3) <= CTS_n; -- Clear To Send + StatReg(4) <= FErr; -- Framing error + StatReg(5) <= OErr; -- Overrun error + StatReg(6) <= PErr; -- Parity error + StatReg(7) <= (RxIEnb and RxDR) or + (RxIEnb and DCDInt) or + (TxIEnb and TxBE); + end if; + end process; + + +----------------------------------------------------------------------------- +-- ACIA Transmit Control +----------------------------------------------------------------------------- + + ACIA_Control : process(CtrlReg, TxDbit) + begin + case CtrlReg(6 downto 5) is + when "00" => -- Disable TX Interrupts, Assert RTS + TxD <= TxDbit; + TxIEnb <= '0'; + when "01" => -- Enable TX interrupts, Assert RTS + TxD <= TxDbit; + TxIEnb <= '1'; + when "10" => -- Disable Tx Interrupts, Clear RTS + TxD <= TxDbit; + TxIEnb <= '0'; + when "11" => -- Disable Tx interrupts, Assert RTS, send break + TxD <= '0'; + TxIEnb <= '0'; + when others => + null; + end case; + + RxIEnb <= CtrlReg(7); + end process; + + tx_process : process(clk, reset) + begin + if reset = '1' then + WriteTR <= '0'; + TxAck <= '0'; + elsif falling_edge(clk) then + WriteTR <= '0'; + TxAck <= '0'; + if TxBE = '0' and TxIdle = '1' then + WriteTR <= '1'; + TxAck <= '1'; + end if; + end if; + end process; + +----------------------------------------------------------------------------- +-- Generate Read / Write strobes. +----------------------------------------------------------------------------- + + ACIA_Read_Write : process(clk, Reset) + begin + if reset = '1' then + CtrlReg <= (others => '0'); + TxReg <= (others => '0'); + ReadRR <= '0'; + ReadSR <= '0'; + TxBE <= '1'; + elsif falling_edge(clk) then + ReadRR <= '0'; + ReadSR <= '0'; + if TxAck = '1' then + TxBE <= '1'; + end if; + if cs = '1' then + if Addr = '0' then -- Control / Status register + if rw = '0' then -- write control register + CtrlReg <= DataIn; + else -- read status register + ReadSR <= '1'; + end if; + else -- Data Register + if rw = '0' then -- write transmiter register + TxReg <= DataIn; + TxBE <= '0'; + else -- read receiver register + ReadRR <= '1'; + end if; + end if; + end if; + end if; + end process; + +--------------------------------------------------------------- +-- Set Data Output Multiplexer +-------------------------------------------------------------- + + ACIA_Data_Mux : process(Addr, RecvReg, StatReg) + begin + if Addr = '1' then + DataOut <= RecvReg; -- read receiver register + else + DataOut <= StatReg; -- read status register + end if; + end process; + + irq <= StatReg(7); + +--------------------------------------------------------------- +-- Data Carrier Detect Edge rising edge detect +--------------------------------------------------------------- + ACIA_DCD_edge : process(reset, clk) + begin + if reset = '1' then + DCDEdge <= '0'; + DCDDel <= '0'; + elsif falling_edge(clk) then + DCDDel <= DCD_n; + DCDEdge <= DCD_n and (not DCDDel); + end if; + end process; + + +--------------------------------------------------------------- +-- Data Carrier Detect Interrupt +--------------------------------------------------------------- +-- If Data Carrier is lost, an interrupt is generated +-- To clear the interrupt, first read the status register +-- then read the data receive register + + ACIA_DCD_Int : process(reset, clk) + begin + if reset = '1' then + DCDInt <= '0'; + DCDState <= DCD_State_Idle; + elsif falling_edge(clk) then + case DCDState is + when DCD_State_Idle => + -- DCD Edge activates interrupt + if DCDEdge = '1' then + DCDInt <= '1'; + DCDState <= DCD_State_Int; + end if; + when DCD_State_Int => + -- To reset DCD interrupt, + -- First read status + if ReadSR = '1' then + DCDState <= DCD_State_Reset; + end if; + when DCD_State_Reset => + -- Then read receive register + if ReadRR = '1' then + DCDInt <= '0'; + DCDState <= DCD_State_Idle; + end if; + when others => + null; + end case; + end if; + end process; + + rts_n <= RxDR; + +end rtl; +

powered by: WebSVN 2.1.0

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