2311 lines
136 KiB
VHDL
2311 lines
136 KiB
VHDL
---------------------------------------------------------------------------------------------------------
|
|
--
|
|
-- Name: zpu_soc.vhd
|
|
-- Created: January 2019
|
|
-- Author(s): Philip Smart
|
|
-- Description: ZPU System On a Chip
|
|
-- This module contains the System on a Chip definition for the ZPU.
|
|
-- Itś purpose is to provide a functional eco-system around the ZPU to actually perform
|
|
-- real tasks. As a basic, boot and stack RAM, UART I/O and Timers are needed to at least
|
|
-- present a monitor via UART for interaction. Upon this can be added an SD card for
|
|
-- disk storage using the Fat FileSystem, SPI etc. Also, as the Wishbone interface is
|
|
-- used in the Evo CPU, any number of 3rd party device IP Cores can be added relatively
|
|
-- easily.
|
|
--
|
|
-- Credits:
|
|
-- Copyright: (c) 2018 Philip Smart <philip.smart@net2net.org>
|
|
--
|
|
-- History: January 2019 - Initial creation.
|
|
--
|
|
---------------------------------------------------------------------------------------------------------
|
|
-- This source file 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 source file 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->.
|
|
---------------------------------------------------------------------------------------------------------
|
|
library ieee;
|
|
library pkgs;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.std_logic_unsigned.all;
|
|
use ieee.numeric_std.all;
|
|
use work.zpu_soc_pkg.all;
|
|
use work.zpu_pkg.all;
|
|
|
|
entity zpu_soc is
|
|
generic (
|
|
SYSCLK_FREQUENCY : integer := SYSTEM_FREQUENCY -- System clock frequency
|
|
);
|
|
port (
|
|
-- Global Control --
|
|
SYSCLK : in std_logic; -- System clock, running at frequency indicated in SYSCLK_FREQUENCY
|
|
MEMCLK : in std_logic; -- Memory clock, running at twice frequency indicated in SYSCLK_FREQUENCY
|
|
RESET_IN : in std_logic;
|
|
|
|
-- UART 0 & 1
|
|
UART_RX_0 : in std_logic;
|
|
UART_TX_0 : out std_logic;
|
|
UART_RX_1 : in std_logic;
|
|
UART_TX_1 : out std_logic;
|
|
|
|
-- SPI signals
|
|
-- SPI_MISO : in std_logic := '1'; -- Allow the SPI interface not to be plumbed in.
|
|
-- SPI_MOSI : out std_logic;
|
|
-- SPI_CLK : out std_logic;
|
|
-- SPI_CS : out std_logic;
|
|
|
|
-- SD Card (SPI) signals
|
|
SDCARD_MISO : in std_logic_vector(SOC_SD_DEVICES-1 downto 0) := (others => '1');
|
|
SDCARD_MOSI : out std_logic_vector(SOC_SD_DEVICES-1 downto 0);
|
|
SDCARD_CLK : out std_logic_vector(SOC_SD_DEVICES-1 downto 0);
|
|
SDCARD_CS : out std_logic_vector(SOC_SD_DEVICES-1 downto 0);
|
|
|
|
-- -- PS/2 signals
|
|
-- PS2K_CLK_IN : in std_logic := '1';
|
|
-- PS2K_DAT_IN : in std_logic := '1';
|
|
-- PS2K_CLK_OUT : out std_logic;
|
|
-- PS2K_DAT_OUT : out std_logic;
|
|
-- PS2M_CLK_IN : in std_logic := '1';
|
|
-- PS2M_DAT_IN : in std_logic := '1';
|
|
-- PS2M_CLK_OUT : out std_logic;
|
|
-- PS2M_DAT_OUT : out std_logic;
|
|
|
|
-- -- I²C signals
|
|
-- I2C_SCL_IO : inout std_logic;
|
|
-- I2C_SDA_IO : inout std_logic;
|
|
|
|
-- -- IOCTL Bus
|
|
-- IOCTL_DOWNLOAD : out std_logic; -- Downloading to FPGA.
|
|
-- IOCTL_UPLOAD : out std_logic; -- Uploading from FPGA.
|
|
-- IOCTL_CLK : out std_logic; -- I/O Clock.
|
|
-- IOCTL_WR : out std_logic; -- Write Enable to FPGA.
|
|
-- IOCTL_RD : out std_logic; -- Read Enable from FPGA.
|
|
-- IOCTL_SENSE : in std_logic; -- Sense to see if HPS accessing ioctl bus.
|
|
-- IOCTL_SELECT : out std_logic; -- Enable IOP control over ioctl bus.
|
|
-- IOCTL_ADDR : out std_logic_vector(24 downto 0); -- Address in FPGA to write into.
|
|
-- IOCTL_DOUT : out std_logic_vector(31 downto 0); -- Data to be written into FPGA.
|
|
-- IOCTL_DIN : in std_logic_vector(31 downto 0); -- Data to be read into HPS.
|
|
|
|
-- SDRAM signals
|
|
SDRAM_CLK : out std_logic; -- sdram is accessed at 100MHz
|
|
SDRAM_CKE : out std_logic; -- clock enable.
|
|
SDRAM_DQ : inout std_logic_vector(15 downto 0); -- 16 bit bidirectional data bus
|
|
SDRAM_ADDR : out std_logic_vector(11 downto 0); -- 12 bit multiplexed address bus
|
|
SDRAM_DQM : out std_logic_vector(1 downto 0); -- two byte masks
|
|
SDRAM_BA : out std_logic_vector(1 downto 0); -- two banks
|
|
SDRAM_CS_n : out std_logic; -- a single chip select
|
|
SDRAM_WE_n : out std_logic; -- write enable
|
|
SDRAM_RAS_n : out std_logic; -- row address select
|
|
SDRAM_CAS_n : out std_logic; -- columns address select
|
|
SDRAM_READY : out std_logic; -- sd ready.
|
|
|
|
-- TCPU signals.
|
|
TCPU_DATA : out std_logic_vector(15 downto 0); -- Data bus
|
|
TCPU_CTL_SET_n : out std_logic; -- Set the transceiver control signals.
|
|
TCPU_CLK_n : in std_logic; -- Z80 Main Clock
|
|
TCPU_NMI_n : in std_logic; -- Z80 NMI converted to 3.3v
|
|
TCPU_INT_n : in std_logic; -- Z80 INT converted to 3.,3v
|
|
TCPU_WAIT_I_n : in std_logic; -- Z80 Wait converted to 3.3v.
|
|
TCPU_BUSACK_I_n : in std_logic; -- Z80 Bus Ack converted to 3.3v.
|
|
TCPU_BUSACK_n : out std_logic; -- CYC sending BUS ACK
|
|
TCPU_BUSRQ_n : out std_logic; -- CYC requesting Z80 bus.
|
|
TCPU_BUSRQ_I_n : in std_logic -- System requesting Z80 bus.
|
|
);
|
|
end entity;
|
|
|
|
architecture rtl of zpu_soc is
|
|
|
|
-- FSM States for the SD card to interface with the controller.
|
|
type SDStateType is
|
|
(
|
|
SD_STATE_IDLE,
|
|
SD_STATE_RESET,
|
|
SD_STATE_RESET_1,
|
|
SD_STATE_WRITE,
|
|
SD_STATE_WRITE_1,
|
|
SD_STATE_WRITE_2,
|
|
SD_STATE_READ,
|
|
SD_STATE_READ_1,
|
|
SD_STATE_READ_2
|
|
);
|
|
|
|
-- Reset processing.
|
|
signal RESET_n : std_logic := '0';
|
|
signal RESET_COUNTER : unsigned(15 downto 0);
|
|
signal RESET_COUNTER_RX : unsigned(15 downto 0);
|
|
|
|
-- Millisecond counter
|
|
signal MICROSEC_DOWN_COUNTER : unsigned(23 downto 0); -- Allow for 16 seconds delay.
|
|
signal MILLISEC_DOWN_COUNTER : unsigned(17 downto 0); -- Allow for 262 seconds delay.
|
|
signal MILLISEC_UP_COUNTER : unsigned(31 downto 0); -- Up counter allowing for 49 days count in milliseconds.
|
|
signal SECOND_DOWN_COUNTER : unsigned(11 downto 0); -- Allow for 1 hour in seconds delay.
|
|
signal MICROSEC_DOWN_TICK : integer range 0 to 150; -- Independent tick register to ensure down counter is accurate.
|
|
signal MILLISEC_DOWN_TICK : integer range 0 to 150*1000; -- Independent tick register to ensure down counter is accurate.
|
|
signal SECOND_DOWN_TICK : integer range 0 to 150*1000000; -- Independent tick register to ensure down counter is accurate.
|
|
signal MILLISEC_UP_TICK : integer range 0 to 150*1000; -- Independent tick register to ensure up counter is accurate.
|
|
signal MICROSEC_DOWN_INTR : std_logic; -- Interrupt when counter reaches 0.
|
|
signal MICROSEC_DOWN_INTR_EN : std_logic; -- Interrupt enable for microsecond down counter.
|
|
signal MILLISEC_DOWN_INTR : std_logic; -- Interrupt when counter reaches 0.
|
|
signal MILLISEC_DOWN_INTR_EN : std_logic; -- Interrupt enable for millisecond down counter.
|
|
signal SECOND_DOWN_INTR : std_logic; -- Interrupt when counter reaches 0.
|
|
signal SECOND_DOWN_INTR_EN : std_logic; -- Interrupt enable for second down counter.
|
|
signal RTC_MICROSEC_TICK : integer range 0 to 150; -- Allow for frequencies upto 150MHz.
|
|
signal RTC_MICROSEC_COUNTER : integer range 0 to 1000; -- Real Time Clock counters.
|
|
signal RTC_MILLISEC_COUNTER : integer range 0 to 1000;
|
|
signal RTC_SECOND_COUNTER : integer range 0 to 60;
|
|
signal RTC_MINUTE_COUNTER : integer range 0 to 60;
|
|
signal RTC_HOUR_COUNTER : integer range 0 to 24;
|
|
signal RTC_DAY_COUNTER : integer range 1 to 32;
|
|
signal RTC_MONTH_COUNTER : integer range 1 to 13;
|
|
signal RTC_YEAR_COUNTER : integer range 0 to 4095;
|
|
signal RTC_TICK_HALT : std_logic;
|
|
|
|
-- Timer register block signals
|
|
signal TIMER_REG_REQ : std_logic;
|
|
signal TIMER1_TICK : std_logic;
|
|
|
|
-- -- SPI Clock counter
|
|
-- signal SPI_TICK : unsigned(8 downto 0);
|
|
-- signal SPICLK_IN : std_logic;
|
|
-- signal SPI_FAST : std_logic;
|
|
|
|
-- -- SPI signals
|
|
-- signal HOST_TO_SPI : std_logic_vector(7 downto 0);
|
|
-- signal SPI_TO_HOST : std_logic_vector(31 downto 0);
|
|
-- signal SPI_WIDE : std_logic;
|
|
-- signal SPI_TRIGGER : std_logic;
|
|
-- signal SPI_BUSY : std_logic;
|
|
-- signal SPI_ACTIVE : std_logic;
|
|
|
|
-- SD Card signals
|
|
type SDAddrArray is array(natural range 0 to SOC_SD_DEVICES-1) of std_logic_vector(WORD_32BIT_RANGE);
|
|
type SDDataArray is array(natural range 0 to SOC_SD_DEVICES-1) of std_logic_vector(7 downto 0);
|
|
type SDErrorArray is array(natural range 0 to SOC_SD_DEVICES-1) of std_logic_vector(15 downto 0);
|
|
--
|
|
signal SD_RESET : std_logic_vector(SOC_SD_DEVICES-1 downto 0); -- active-high, synchronous reset.
|
|
signal SD_RD : std_logic_vector(SOC_SD_DEVICES-1 downto 0); -- active-high read block request.
|
|
signal SD_WR : std_logic_vector(SOC_SD_DEVICES-1 downto 0); -- active-high write block request.
|
|
signal SD_CONTINUE : std_logic_vector(SOC_SD_DEVICES-1 downto 0); -- If true, inc address and continue R/W.
|
|
signal SD_CARD_TYPE : std_logic_vector(SOC_SD_DEVICES-1 downto 0); -- Type of card, 0 = SD, 1 = SDHC
|
|
signal SD_ADDR : SDAddrArray; -- Block address.
|
|
signal SD_DATA_READ : SDDataArray; -- Data read from block.
|
|
signal SD_DATA_WRITE : std_logic_vector(7 downto 0); -- Data byte to write to block.
|
|
signal SD_DATA_VALID : std_logic; -- Flag to indicate when data has been received (rx).
|
|
signal SD_DATA_REQ : std_logic; -- Flag to indicate when data is valid for tx.
|
|
signal SD_CHANNEL : integer range 0 to SOC_SD_DEVICES-1; -- Active channel in the state machine.
|
|
signal SD_BUSY : std_logic_vector(SOC_SD_DEVICES-1 downto 0); -- High when controller is busy performing some operation.
|
|
signal SD_HNDSHK_IN : std_logic_vector(SOC_SD_DEVICES-1 downto 0); -- High when host has data to give or has taken data.
|
|
signal SD_HNDSHK_OUT : std_logic_vector(SOC_SD_DEVICES-1 downto 0); -- High when controller has taken data or has data to give.
|
|
signal SD_ERROR : SDErrorArray; -- Card error occurred (1).
|
|
signal SD_OVERRUN : std_logic; -- Receive data overrun flag.
|
|
signal SD_STATE : SDStateType; -- State machine states.
|
|
signal SD_RESET_TIMER : integer range 0 to 100; -- 100ns reset timer, allows for SYSFREQ = 10 .. 100MHz.
|
|
|
|
-- UART signals
|
|
signal UART0_WR : std_logic;
|
|
signal UART0_ADDR : std_logic;
|
|
signal UART0_DATA_OUT : std_logic_vector(31 downto 0);
|
|
signal UART0_TX_INTR : std_logic;
|
|
signal UART0_RX_INTR : std_logic;
|
|
signal UART1_WR : std_logic;
|
|
signal UART1_ADDR : std_logic;
|
|
signal UART1_DATA_OUT : std_logic_vector(31 downto 0);
|
|
signal UART1_TX_INTR : std_logic;
|
|
signal UART1_RX_INTR : std_logic;
|
|
signal UART1_TX : std_logic;
|
|
signal UART2_TX : std_logic;
|
|
|
|
-- -- PS2 signals
|
|
-- signal PS2_INT : std_logic;
|
|
|
|
-- -- PS2 Keyboard Signals.
|
|
-- signal KBD_IDLE : std_logic;
|
|
-- signal KBD_RECV : std_logic;
|
|
-- signal KBD_RECV_REG : std_logic;
|
|
-- signal KBD_SEND_BUSY : std_logic;
|
|
-- signal KBD_SEND_TRIGGER : std_logic;
|
|
-- signal KBD_SEND_DONE : std_logic;
|
|
-- signal KBD_SEND_BYTE : std_logic_vector(7 downto 0);
|
|
-- signal KBD_RECV_BYTE : std_logic_vector(10 downto 0);
|
|
|
|
-- -- I²C Signals.
|
|
-- signal SCL_PAD_IN : std_logic; -- i2c clock line input
|
|
-- signal SCL_PAD_OUT : std_logic; -- i2c clock line output
|
|
-- signal SCL_PAD_OE : std_logic; -- i2c clock line output enable, active low
|
|
-- signal SDA_PAD_IN : std_logic; -- i2c data line input
|
|
-- signal SDA_PAD_OUT : std_logic; -- i2c data line output
|
|
-- signal SDA_PAD_OE : std_logic; -- i2c data line output enable, active low
|
|
-- signal WB_DATA_READ_I2C : std_logic_vector(WORD_32BIT_RANGE); -- i2c data as 32bit word for placing on WB bus.
|
|
-- signal WB_I2C_ACK : std_logic;
|
|
-- signal WB_I2C_HALT : std_logic;
|
|
-- signal WB_I2C_ERR : std_logic;
|
|
-- signal WB_I2C_CS : std_logic;
|
|
-- signal WB_I2C_IRQ : std_logic;
|
|
|
|
|
|
-- Wishbone control signals.
|
|
signal WB_SDRAM_ACK : std_logic;
|
|
signal WB_SDRAM_STB : std_logic;
|
|
signal WB_DATA_READ_SDRAM : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal WB_SDRAM_SELECT : std_logic;
|
|
signal WB_SDRAM_WREN : std_logic;
|
|
signal SRD : std_logic;
|
|
signal SWR : std_logic;
|
|
signal dataMask : std_logic_vector(3 downto 0);
|
|
signal dataWord : std_logic_vector(31 downto 0);
|
|
|
|
-- ZPU signals
|
|
signal MEM_BUSY : std_logic;
|
|
signal IO_WAIT_SD : std_logic;
|
|
-- signal IO_WAIT_SPI : std_logic;
|
|
-- signal IO_WAIT_PS2 : std_logic;
|
|
signal IO_WAIT_INTR : std_logic;
|
|
signal IO_WAIT_TIMER1 : std_logic;
|
|
signal MEM_DATA_READ : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal MEM_DATA_WRITE : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal MEM_ADDR : std_logic_vector(ADDR_BIT_RANGE);
|
|
signal MEM_WRITE_ENABLE : std_logic;
|
|
signal MEM_WRITE_BYTE_ENABLE : std_logic;
|
|
signal MEM_WRITE_HWORD_ENABLE : std_logic;
|
|
signal MEM_READ_ENABLE : std_logic;
|
|
signal MEM_DATA_READ_INSN : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal MEM_ADDR_INSN : std_logic_vector(ADDR_BIT_RANGE);
|
|
signal MEM_READ_ENABLE_INSN : std_logic;
|
|
signal IO_DATA_READ : std_logic_vector(WORD_32BIT_RANGE);
|
|
-- signal IO_DATA_READ_SPI : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal IO_DATA_READ_SD : std_logic_vector(WORD_32BIT_RANGE);
|
|
-- signal IO_DATA_READ_PS2 : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal IO_DATA_READ_INTRCTL : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal IO_DATA_READ_SOCCFG : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal IO_DATA_READ_TCPU : std_logic_vector(WORD_32BIT_RANGE);
|
|
|
|
-- ZPU ROM/BRAM/RAM/Stack signals.
|
|
signal MEM_A_WRITE_ENABLE : std_logic;
|
|
signal MEM_A_ADDR : std_logic_vector(ADDR_32BIT_RANGE);
|
|
signal MEM_A_WRITE : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal MEM_B_WRITE_ENABLE : std_logic;
|
|
signal MEM_B_ADDR : std_logic_vector(ADDR_32BIT_RANGE);
|
|
signal MEM_B_WRITE : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal MEM_A_READ : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal MEM_B_READ : std_logic_vector(WORD_32BIT_RANGE);
|
|
|
|
-- Master Wishbone Memory/IO bus interface.
|
|
signal WB_CLK_I : std_logic;
|
|
signal WB_RST_I : std_logic;
|
|
signal WB_ACK_I : std_logic;
|
|
signal WB_DAT_I : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal WB_DAT_O : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal WB_ADR_O : std_logic_vector(ADDR_BIT_RANGE);
|
|
signal WB_CYC_O : std_logic;
|
|
signal WB_STB_O : std_logic;
|
|
signal WB_CTI_O : std_logic_vector(2 downto 0);
|
|
signal WB_WE_O : std_logic;
|
|
signal WB_SEL_O : std_logic_vector(WORD_4BYTE_RANGE);
|
|
signal WB_HALT_I : std_logic;
|
|
signal WB_ERR_I : std_logic;
|
|
signal WB_INTA_I : std_logic;
|
|
|
|
-- Interrupt signals
|
|
signal INT_TRIGGERS : std_logic_vector(SOC_INTR_MAX downto 0);
|
|
signal INT_ENABLE : std_logic_vector(SOC_INTR_MAX downto 0);
|
|
signal INT_STATUS : std_logic_vector(SOC_INTR_MAX downto 0);
|
|
signal INT_REQ : std_logic;
|
|
signal INT_TRIGGER : std_logic;
|
|
signal INT_ACK : std_logic;
|
|
signal INT_DONE : std_logic;
|
|
|
|
-- ZPU ROM/BRAM/RAM
|
|
signal BRAM_SELECT : std_logic;
|
|
signal RAM_SELECT : std_logic;
|
|
signal SDRAM_SELECT : std_logic;
|
|
signal BRAM_WREN : std_logic;
|
|
signal RAM_WREN : std_logic;
|
|
signal SDRAM_WREN : std_logic;
|
|
signal SDRAM_RDEN : std_logic;
|
|
signal SDRAM_MEM_BUSY : std_logic;
|
|
signal BRAM_DATA_READ : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal RAM_DATA_READ : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal SDRAM_DATA_READ : std_logic_vector(WORD_32BIT_RANGE);
|
|
|
|
-- IO Chip selects
|
|
signal IO_SELECT : std_logic; -- IO Range 0x<msb=0>7FFFFxxx of devices connected to the ZPU system bus.
|
|
signal WB_IO_SELECT : std_logic; -- IO Range of the ZPU CPU 0x<msb=1>F00000 .. 0x<nsb=1>FFFFFF
|
|
signal WB_IO_SOC_SELECT : std_logic; -- IO Range used within the SoC for small devices, upto 256 locations per device. 0x<msb=1>1F000xx
|
|
signal IO_UART_SELECT : std_logic; -- Uart Range 0xFFFFFAxx
|
|
signal IO_INTR_SELECT : std_logic; -- Interrupt Range 0xFFFFFBxx
|
|
signal IO_TIMER_SELECT : std_logic; -- Timer Range 0xFFFFFCxx
|
|
-- signal IO_SPI_SELECT : std_logic; -- SPI Range 0xFFFFFDxx
|
|
-- signal IO_PS2_SELECT : std_logic; -- PS2 Range 0xFFFFFExx
|
|
signal TCPU_CS : std_logic; -- 0x700-80F
|
|
signal SD_CS : std_logic; -- 0x900-93F
|
|
signal UART0_CS : std_logic; -- 0xA00-C0F
|
|
signal UART1_CS : std_logic; -- 0xA10-A1F
|
|
signal INTR0_CS : std_logic; -- 0xB00-B0F
|
|
signal TIMER0_CS : std_logic; -- 0xC00-C0F Millisecond timer.
|
|
signal TIMER1_CS : std_logic; -- 0xC10-C1F
|
|
-- signal SPI0_CS : std_logic; -- 0xD00-D0F
|
|
-- signal PS2_CS : std_logic; -- 0xE00-E0F
|
|
signal SOCCFG_CS : std_logic; -- 0xF00-F0F
|
|
|
|
function to_std_logic(L: boolean) return std_logic is
|
|
begin
|
|
if L then
|
|
return('1');
|
|
else
|
|
return('0');
|
|
end if;
|
|
end function to_std_logic;
|
|
begin
|
|
|
|
--
|
|
-- Instantiation
|
|
--
|
|
-- Main CPU
|
|
ZPUFLEX: if ZPU_FLEX = 1 generate
|
|
ZPU0 : zpu_core_flex
|
|
generic map (
|
|
IMPL_MULTIPLY => true,
|
|
IMPL_COMPARISON_SUB => true,
|
|
IMPL_EQBRANCH => true,
|
|
IMPL_STOREBH => false,
|
|
IMPL_LOADBH => false,
|
|
IMPL_CALL => true,
|
|
IMPL_SHIFT => true,
|
|
IMPL_XOR => true,
|
|
CACHE => true,
|
|
-- IMPL_EMULATION => minimal,
|
|
-- REMAP_STACK => false --true, -- We need to remap the Boot ROM / Stack RAM so we can access SDRAM
|
|
CLK_FREQ => SYSCLK_FREQUENCY,
|
|
STACK_ADDR => SOC_STACK_ADDR -- Initial stack address on CPU start.
|
|
)
|
|
port map (
|
|
clk => SYSCLK,
|
|
reset => not RESET_n,
|
|
enable => '1',
|
|
in_mem_busy => MEM_BUSY,
|
|
mem_read => MEM_DATA_READ,
|
|
mem_write => MEM_DATA_WRITE,
|
|
out_mem_addr => MEM_ADDR,
|
|
out_mem_writeEnable => MEM_WRITE_ENABLE,
|
|
out_mem_hEnable => MEM_WRITE_HWORD_ENABLE,
|
|
out_mem_bEnable => MEM_WRITE_BYTE_ENABLE,
|
|
out_mem_readEnable => MEM_READ_ENABLE,
|
|
interrupt_request => INT_TRIGGER,
|
|
interrupt_ack => INT_ACK, -- Interrupt acknowledge, ZPU has entered Interrupt Service Routine.
|
|
interrupt_done => INT_DONE, -- Interrupt service routine completed/done.
|
|
break => open,
|
|
debug_txd => UART2_TX, -- Debug serial output.
|
|
--
|
|
MEM_A_WRITE_ENABLE => MEM_A_WRITE_ENABLE,
|
|
MEM_A_ADDR => MEM_A_ADDR,
|
|
MEM_A_WRITE => MEM_A_WRITE,
|
|
MEM_B_WRITE_ENABLE => MEM_B_WRITE_ENABLE,
|
|
MEM_B_ADDR => MEM_B_ADDR,
|
|
MEM_B_WRITE => MEM_B_WRITE,
|
|
MEM_A_READ => MEM_A_READ,
|
|
MEM_B_READ => MEM_B_READ
|
|
);
|
|
end generate;
|
|
ZPUSMALL: if ZPU_SMALL = 1 generate
|
|
ZPU0 : zpu_core_small
|
|
generic map (
|
|
CLK_FREQ => SYSCLK_FREQUENCY,
|
|
STACK_ADDR => SOC_STACK_ADDR -- Initial stack address on CPU start.
|
|
)
|
|
port map (
|
|
clk => SYSCLK,
|
|
areset => not RESET_n,
|
|
enable => '1',
|
|
in_mem_busy => MEM_BUSY,
|
|
mem_read => MEM_DATA_READ,
|
|
mem_write => MEM_DATA_WRITE,
|
|
out_mem_addr => MEM_ADDR,
|
|
out_mem_writeEnable => MEM_WRITE_ENABLE,
|
|
out_mem_hEnable => MEM_WRITE_HWORD_ENABLE,
|
|
out_mem_bEnable => MEM_WRITE_BYTE_ENABLE,
|
|
out_mem_readEnable => MEM_READ_ENABLE,
|
|
mem_writeMask => open,
|
|
interrupt_request => INT_TRIGGER,
|
|
interrupt_ack => INT_ACK, -- Interrupt acknowledge, ZPU has entered Interrupt Service Routine.
|
|
interrupt_done => INT_DONE, -- Interrupt service routine completed/done.
|
|
break => open,
|
|
debug_txd => UART2_TX, -- Debug serial output.
|
|
MEM_A_WRITE_ENABLE => MEM_A_WRITE_ENABLE,
|
|
MEM_A_ADDR => MEM_A_ADDR,
|
|
MEM_A_WRITE => MEM_A_WRITE,
|
|
MEM_B_WRITE_ENABLE => MEM_B_WRITE_ENABLE,
|
|
MEM_B_ADDR => MEM_B_ADDR,
|
|
MEM_B_WRITE => MEM_B_WRITE,
|
|
MEM_A_READ => MEM_A_READ,
|
|
MEM_B_READ => MEM_B_READ
|
|
);
|
|
end generate;
|
|
ZPUMEDIUM: if ZPU_MEDIUM = 1 generate
|
|
ZPU0 : zpu_core_medium
|
|
generic map (
|
|
CLK_FREQ => SYSCLK_FREQUENCY,
|
|
STACK_ADDR => SOC_STACK_ADDR -- Initial stack address on CPU start.
|
|
)
|
|
port map (
|
|
clk => SYSCLK,
|
|
areset => not RESET_n,
|
|
enable => '1',
|
|
in_mem_busy => MEM_BUSY,
|
|
mem_read => MEM_DATA_READ,
|
|
mem_write => MEM_DATA_WRITE,
|
|
out_mem_addr => MEM_ADDR,
|
|
out_mem_writeEnable => MEM_WRITE_ENABLE,
|
|
out_mem_hEnable => MEM_WRITE_HWORD_ENABLE,
|
|
out_mem_bEnable => MEM_WRITE_BYTE_ENABLE,
|
|
out_mem_readEnable => MEM_READ_ENABLE,
|
|
mem_writeMask => open,
|
|
interrupt_request => INT_TRIGGER,
|
|
interrupt_ack => INT_ACK, -- Interrupt acknowledge, ZPU has entered Interrupt Service Routine.
|
|
interrupt_done => INT_DONE, -- Interrupt service routine completed/done.
|
|
break => open,
|
|
debug_txd => UART2_TX -- Debug serial output.
|
|
);
|
|
end generate;
|
|
ZPUEVO: if ZPU_EVO = 1 generate
|
|
ZPU0 : zpu_core_evo
|
|
generic map (
|
|
-- Optional hardware features to be implemented.
|
|
IMPL_HW_BYTE_WRITE => EVO_USE_HW_BYTE_WRITE, -- Enable use of hardware direct byte write rather than read 33bits-modify 8 bits-write 32bits.
|
|
IMPL_HW_WORD_WRITE => EVO_USE_HW_WORD_WRITE, -- Enable use of hardware direct byte write rather than read 32bits-modify 16 bits-write 32bits.
|
|
IMPL_OPTIMIZE_IM => IMPL_EVO_OPTIMIZE_IM, -- If the instruction cache is enabled, optimise Im instructions to gain speed.
|
|
IMPL_USE_INSN_BUS => SOC_IMPL_INSN_BRAM, -- Use a seperate bus to read instruction memory, normally implemented in BRAM.
|
|
IMPL_USE_WB_BUS => EVO_USE_WB_BUS, -- Use the wishbone interface in addition to direct access bus.
|
|
-- Optional instructions to be implemented in hardware:
|
|
IMPL_ASHIFTLEFT => IMPL_EVO_ASHIFTLEFT, -- Arithmetic Shift Left (uses same logic so normally combined with ASHIFTRIGHT and LSHIFTRIGHT).
|
|
IMPL_ASHIFTRIGHT => IMPL_EVO_ASHIFTRIGHT, -- Arithmetic Shift Right.
|
|
IMPL_CALL => IMPL_EVO_CALL, -- Call to direct address.
|
|
IMPL_CALLPCREL => IMPL_EVO_CALLPCREL, -- Call to indirect address (add offset to program counter).
|
|
IMPL_DIV => IMPL_EVO_DIV, -- 32bit signed division.
|
|
IMPL_EQ => IMPL_EVO_EQ, -- Equality test.
|
|
IMPL_EXTENDED_INSN => IMPL_EVO_EXTENDED_INSN, -- Extended multibyte instruction set.
|
|
IMPL_FIADD32 => IMPL_EVO_FIADD32, -- Fixed point Q17.15 addition.
|
|
IMPL_FIDIV32 => IMPL_EVO_FIDIV32, -- Fixed point Q17.15 division.
|
|
IMPL_FIMULT32 => IMPL_EVO_FIMULT32, -- Fixed point Q17.15 multiplication.
|
|
IMPL_LOADB => IMPL_EVO_LOADB, -- Load single byte from memory.
|
|
IMPL_LOADH => IMPL_EVO_LOADH, -- Load half word (16bit) from memory.
|
|
IMPL_LSHIFTRIGHT => IMPL_EVO_LSHIFTRIGHT, -- Logical shift right.
|
|
IMPL_MOD => IMPL_EVO_MOD, -- 32bit modulo (remainder after division).
|
|
IMPL_MULT => IMPL_EVO_MULT, -- 32bit signed multiplication.
|
|
IMPL_NEG => IMPL_EVO_NEG, -- Negate value in TOS.
|
|
IMPL_NEQ => IMPL_EVO_NEQ, -- Not equal test.
|
|
IMPL_POPPCREL => IMPL_EVO_POPPCREL, -- Pop a value into the Program Counter from a location relative to the Stack Pointer.
|
|
IMPL_PUSHSPADD => IMPL_EVO_PUSHSPADD, -- Add a value to the Stack pointer and push it onto the stack.
|
|
IMPL_STOREB => IMPL_EVO_STOREB, -- Store/Write a single byte to memory/IO.
|
|
IMPL_STOREH => IMPL_EVO_STOREH, -- Store/Write a half word (16bit) to memory/IO.
|
|
IMPL_SUB => IMPL_EVO_SUB, -- 32bit signed subtract.
|
|
IMPL_XOR => IMPL_EVO_XOR, -- Exclusive or of value in TOS.
|
|
-- Size/Control parameters for the optional hardware.
|
|
MAX_INSNRAM_SIZE => (2**(SOC_MAX_ADDR_INSN_BRAM_BIT)), -- Maximum size of the optional instruction BRAM on the INSN Bus.
|
|
MAX_L1CACHE_BITS => MAX_EVO_L1CACHE_BITS, -- Maximum size in instructions of the Level 0 instruction cache governed by the number of bits, ie. 8 = 256 instruction cache.
|
|
MAX_L2CACHE_BITS => MAX_EVO_L2CACHE_BITS, -- Maximum bit size in bytes of the Level 2 instruction cache governed by the number of bits, ie. 8 = 256 byte cache.
|
|
MAX_MXCACHE_BITS => MAX_EVO_MXCACHE_BITS, -- Maximum size of the memory transaction cache governed by the number of bits.
|
|
RESET_ADDR_CPU => SOC_RESET_ADDR_CPU, -- Initial start address of the CPU.
|
|
START_ADDR_MEM => SOC_START_ADDR_MEM, -- Start address of program memory.
|
|
STACK_ADDR => SOC_STACK_ADDR, -- Initial stack address on CPU start.
|
|
CLK_FREQ => SYSCLK_FREQUENCY -- System clock frequency.
|
|
)
|
|
port map (
|
|
CLK => SYSCLK,
|
|
RESET => not RESET_n,
|
|
ENABLE => '1',
|
|
MEM_BUSY => MEM_BUSY,
|
|
MEM_DATA_IN => MEM_DATA_READ,
|
|
MEM_DATA_OUT => MEM_DATA_WRITE,
|
|
MEM_ADDR => MEM_ADDR,
|
|
MEM_WRITE_ENABLE => MEM_WRITE_ENABLE,
|
|
MEM_READ_ENABLE => MEM_READ_ENABLE,
|
|
MEM_WRITE_BYTE => MEM_WRITE_BYTE_ENABLE,
|
|
MEM_WRITE_HWORD => MEM_WRITE_HWORD_ENABLE,
|
|
-- Instruction memory path.
|
|
MEM_BUSY_INSN => '0',
|
|
MEM_DATA_IN_INSN => MEM_DATA_READ_INSN,
|
|
MEM_ADDR_INSN => MEM_ADDR_INSN,
|
|
MEM_READ_ENABLE_INSN => MEM_READ_ENABLE_INSN,
|
|
-- Master Wishbone Memory/IO bus interface.
|
|
WB_CLK_I => WB_CLK_I,
|
|
WB_RST_I => not RESET_n,
|
|
WB_ACK_I => WB_ACK_I,
|
|
WB_DAT_I => WB_DAT_I,
|
|
WB_DAT_O => WB_DAT_O,
|
|
WB_ADR_O => WB_ADR_O,
|
|
WB_CYC_O => WB_CYC_O,
|
|
WB_STB_O => WB_STB_O,
|
|
WB_CTI_O => WB_CTI_O,
|
|
WB_WE_O => WB_WE_O,
|
|
WB_SEL_O => WB_SEL_O,
|
|
WB_HALT_I => WB_HALT_I,
|
|
WB_ERR_I => WB_ERR_I,
|
|
WB_INTA_I => WB_INTA_I,
|
|
--
|
|
INT_REQ => INT_TRIGGER,
|
|
INT_ACK => INT_ACK, -- Interrupt acknowledge, ZPU has entered Interrupt Service Routine.
|
|
INT_DONE => INT_DONE, -- Interrupt service routine completed/done.
|
|
BREAK => open, -- A break instruction encountered.
|
|
CONTINUE => '1', -- When break activated, processing stops. Setting CONTINUE to logic 1 resumes processing with next instruction.
|
|
DEBUG_TXD => UART2_TX -- Debug serial output.
|
|
);
|
|
end generate;
|
|
ZPUEVOMIN: if ZPU_EVO_MINIMAL = 1 generate
|
|
ZPU0 : zpu_core_evo
|
|
generic map (
|
|
-- Optional hardware features to be implemented.
|
|
IMPL_HW_BYTE_WRITE => EVO_USE_HW_BYTE_WRITE, -- Enable use of hardware direct byte write rather than read 33bits-modify 8 bits-write 32bits.
|
|
IMPL_HW_WORD_WRITE => EVO_USE_HW_WORD_WRITE, -- Enable use of hardware direct byte write rather than read 32bits-modify 16 bits-write 32bits.
|
|
IMPL_OPTIMIZE_IM => IMPL_EVOM_OPTIMIZE_IM, -- If the instruction cache is enabled, optimise Im instructions to gain speed.
|
|
IMPL_USE_INSN_BUS => SOC_IMPL_INSN_BRAM, -- Use a seperate bus to read instruction memory, normally implemented in BRAM.
|
|
IMPL_USE_WB_BUS => EVO_USE_WB_BUS, -- Use the wishbone interface in addition to direct access bus.
|
|
-- Optional instructions to be implemented in hardware:
|
|
IMPL_ASHIFTLEFT => IMPL_EVOM_ASHIFTLEFT, -- Arithmetic Shift Left (uses same logic so normally combined with ASHIFTRIGHT and LSHIFTRIGHT).
|
|
IMPL_ASHIFTRIGHT => IMPL_EVOM_ASHIFTRIGHT, -- Arithmetic Shift Right.
|
|
IMPL_CALL => IMPL_EVOM_CALL, -- Call to direct address.
|
|
IMPL_CALLPCREL => IMPL_EVOM_CALLPCREL, -- Call to indirect address (add offset to program counter).
|
|
IMPL_DIV => IMPL_EVOM_DIV, -- 32bit signed division.
|
|
IMPL_EQ => IMPL_EVOM_EQ, -- Equality test.
|
|
IMPL_EXTENDED_INSN => IMPL_EVOM_EXTENDED_INSN, -- Extended multibyte instruction set.
|
|
IMPL_FIADD32 => IMPL_EVOM_FIADD32, -- Fixed point Q17.15 addition.
|
|
IMPL_FIDIV32 => IMPL_EVOM_FIDIV32, -- Fixed point Q17.15 division.
|
|
IMPL_FIMULT32 => IMPL_EVOM_FIMULT32, -- Fixed point Q17.15 multiplication.
|
|
IMPL_LOADB => IMPL_EVOM_LOADB, -- Load single byte from memory.
|
|
IMPL_LOADH => IMPL_EVOM_LOADH, -- Load half word (16bit) from memory.
|
|
IMPL_LSHIFTRIGHT => IMPL_EVOM_LSHIFTRIGHT, -- Logical shift right.
|
|
IMPL_MOD => IMPL_EVOM_MOD, -- 32bit modulo (remainder after division).
|
|
IMPL_MULT => IMPL_EVOM_MULT, -- 32bit signed multiplication.
|
|
IMPL_NEG => IMPL_EVOM_NEG, -- Negate value in TOS.
|
|
IMPL_NEQ => IMPL_EVOM_NEQ, -- Not equal test.
|
|
IMPL_POPPCREL => IMPL_EVOM_POPPCREL, -- Pop a value into the Program Counter from a location relative to the Stack Pointer.
|
|
IMPL_PUSHSPADD => IMPL_EVOM_PUSHSPADD, -- Add a value to the Stack pointer and push it onto the stack.
|
|
IMPL_STOREB => IMPL_EVOM_STOREB, -- Store/Write a single byte to memory/IO.
|
|
IMPL_STOREH => IMPL_EVOM_STOREH, -- Store/Write a half word (16bit) to memory/IO.
|
|
IMPL_SUB => IMPL_EVOM_SUB, -- 32bit signed subtract.
|
|
IMPL_XOR => IMPL_EVOM_XOR, -- Exclusive or of value in TOS.
|
|
-- Size/Control parameters for the optional hardware.
|
|
MAX_INSNRAM_SIZE => (2**(SOC_MAX_ADDR_INSN_BRAM_BIT)), -- Maximum size of the optional instruction BRAM on the INSN Bus.
|
|
MAX_L1CACHE_BITS => MAX_EVO_MIN_L1CACHE_BITS, -- Maximum size in instructions of the Level 0 instruction cache governed by the number of bits, ie. 8 = 256 instruction cache.
|
|
MAX_L2CACHE_BITS => MAX_EVO_MIN_L2CACHE_BITS, -- Maximum size in bytes of the Level 2 instruction cache governed by the number of bits, ie. 8 = 256 byte cache.
|
|
MAX_MXCACHE_BITS => MAX_EVO_MIN_MXCACHE_BITS, -- Maximum size of the memory transaction cache governed by the number of bits.
|
|
RESET_ADDR_CPU => SOC_RESET_ADDR_CPU, -- Initial start address of the CPU.
|
|
START_ADDR_MEM => SOC_START_ADDR_MEM, -- Start address of program memory.
|
|
STACK_ADDR => SOC_STACK_ADDR, -- Initial stack address on CPU start.
|
|
CLK_FREQ => SYSCLK_FREQUENCY -- System clock frequency.
|
|
)
|
|
port map (
|
|
CLK => SYSCLK,
|
|
RESET => not RESET_n,
|
|
ENABLE => '1',
|
|
MEM_BUSY => MEM_BUSY,
|
|
MEM_DATA_IN => MEM_DATA_READ,
|
|
MEM_DATA_OUT => MEM_DATA_WRITE,
|
|
MEM_ADDR => MEM_ADDR,
|
|
MEM_WRITE_ENABLE => MEM_WRITE_ENABLE,
|
|
MEM_READ_ENABLE => MEM_READ_ENABLE,
|
|
MEM_WRITE_BYTE => MEM_WRITE_BYTE_ENABLE,
|
|
MEM_WRITE_HWORD => MEM_WRITE_HWORD_ENABLE,
|
|
-- Instruction memory path.
|
|
MEM_BUSY_INSN => '0',
|
|
MEM_DATA_IN_INSN => MEM_DATA_READ_INSN,
|
|
MEM_ADDR_INSN => MEM_ADDR_INSN,
|
|
MEM_READ_ENABLE_INSN => MEM_READ_ENABLE_INSN,
|
|
-- Master Wishbone Memory/IO bus interface.
|
|
WB_CLK_I => WB_CLK_I,
|
|
WB_RST_I => not RESET_n,
|
|
WB_ACK_I => WB_ACK_I,
|
|
WB_DAT_I => WB_DAT_I,
|
|
WB_DAT_O => WB_DAT_O,
|
|
WB_ADR_O => WB_ADR_O,
|
|
WB_CYC_O => WB_CYC_O,
|
|
WB_STB_O => WB_STB_O,
|
|
WB_CTI_O => WB_CTI_O,
|
|
WB_WE_O => WB_WE_O,
|
|
WB_SEL_O => WB_SEL_O,
|
|
WB_HALT_I => WB_HALT_I,
|
|
WB_ERR_I => WB_ERR_I,
|
|
WB_INTA_I => WB_INTA_I,
|
|
--
|
|
INT_REQ => INT_TRIGGER,
|
|
INT_ACK => INT_ACK, -- Interrupt acknowledge, ZPU has entered Interrupt Service Routine.
|
|
INT_DONE => INT_DONE, -- Interrupt service routine completed/done.
|
|
BREAK => open, -- A break instruction encountered.
|
|
CONTINUE => '1', -- When break activated, processing stops. Setting CONTINUE to logic 1 resumes processing with next instruction.
|
|
DEBUG_TXD => UART2_TX -- Debug serial output.
|
|
);
|
|
end generate;
|
|
|
|
-- ROM
|
|
ZPUROMSMALL : if (ZPU_SMALL = 1 or ZPU_FLEX = 1) and SOC_IMPL_BRAM = true generate
|
|
ZPUROM : entity work.BootROM
|
|
port map (
|
|
clk => SYSCLK,
|
|
memAWriteEnable => MEM_A_WRITE_ENABLE,
|
|
memAAddr => MEM_A_ADDR(ADDR_32BIT_BRAM_RANGE),
|
|
memAWrite => MEM_A_WRITE,
|
|
memBWriteEnable => MEM_B_WRITE_ENABLE,
|
|
memBAddr => MEM_B_ADDR(ADDR_32BIT_BRAM_RANGE),
|
|
memBWrite => MEM_B_WRITE,
|
|
memARead => MEM_A_READ,
|
|
memBRead => MEM_B_READ
|
|
);
|
|
end generate;
|
|
|
|
-- This block should provide byte addressable dual port BRAM for the Flex but for some reason Quartus quarks when compiling when the B port is used for writes. Not sure why
|
|
-- but needs revisiting as it will gain some performance improvements for the flex core.
|
|
--ZPUROMFLEX : if ZPU_FLEX = 1 and SOC_IMPL_BRAM = true generate
|
|
-- ZPUROM : entity work.DualPortBootBRAM
|
|
-- generic map (
|
|
-- addrbits => SOC_MAX_ADDR_BRAM_BIT
|
|
-- )
|
|
-- port map (
|
|
-- clk => SYSCLK,
|
|
-- memAAddr => MEM_A_ADDR(17 downto 2),
|
|
-- memAWriteEnable => MEM_A_WRITE_ENABLE,
|
|
-- memAWriteByte => MEM_WRITE_BYTE_ENABLE,
|
|
-- memAWriteHalfWord => MEM_WRITE_HWORD_ENABLE,
|
|
-- memAWrite => MEM_A_WRITE,
|
|
-- memARead => MEM_A_READ,
|
|
|
|
-- memBAddr => MEM_B_ADDR(ADDR_32BIT_BRAM_RANGE),
|
|
-- memBWrite => MEM_B_WRITE,
|
|
-- memBWriteEnable => MEM_B_WRITE_ENABLE,
|
|
-- memBRead => MEM_B_READ
|
|
-- );
|
|
--end generate;
|
|
|
|
ZPUROMMEDIUM : if ZPU_MEDIUM = 1 and SOC_IMPL_BRAM = true generate
|
|
ZPUROM : entity work.BootROM
|
|
port map (
|
|
clk => SYSCLK,
|
|
memAWriteEnable => BRAM_WREN,
|
|
memAAddr => MEM_ADDR(ADDR_32BIT_BRAM_RANGE),
|
|
memAWrite => MEM_DATA_WRITE,
|
|
memBWriteEnable => '0',
|
|
memBAddr => MEM_ADDR(ADDR_32BIT_BRAM_RANGE),
|
|
memBWrite => (others => '0'),
|
|
memARead => open,
|
|
memBRead => BRAM_DATA_READ
|
|
);
|
|
end generate;
|
|
|
|
-- Evo system BRAM, dual port to allow for seperate instruction bus read.
|
|
ZPUDPBRAMEVO : if (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and SOC_IMPL_INSN_BRAM = true and SOC_IMPL_BRAM = true generate
|
|
ZPUBRAM : entity work.DualPortBootBRAM
|
|
generic map (
|
|
addrbits => SOC_MAX_ADDR_BRAM_BIT
|
|
)
|
|
port map (
|
|
clk => SYSCLK,
|
|
memAAddr => MEM_ADDR(ADDR_BIT_BRAM_RANGE),
|
|
memAWriteEnable => BRAM_WREN,
|
|
memAWriteByte => MEM_WRITE_BYTE_ENABLE,
|
|
memAWriteHalfWord => MEM_WRITE_HWORD_ENABLE,
|
|
memAWrite => MEM_DATA_WRITE,
|
|
memARead => BRAM_DATA_READ,
|
|
|
|
memBAddr => MEM_ADDR_INSN(ADDR_32BIT_BRAM_RANGE),
|
|
memBWrite => (others => '0'),
|
|
memBWriteEnable => '0',
|
|
memBRead => MEM_DATA_READ_INSN
|
|
);
|
|
end generate;
|
|
-- Evo system BRAM, single port as no seperate instruction bus configured.
|
|
ZPUBRAMEVO : if (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and SOC_IMPL_INSN_BRAM = false and SOC_IMPL_BRAM = true generate
|
|
ZPUBRAM : entity work.SinglePortBootBRAM
|
|
generic map (
|
|
addrbits => SOC_MAX_ADDR_BRAM_BIT
|
|
)
|
|
port map (
|
|
clk => SYSCLK,
|
|
memAAddr => MEM_ADDR(ADDR_BIT_BRAM_RANGE),
|
|
memAWriteEnable => BRAM_WREN,
|
|
memAWriteByte => MEM_WRITE_BYTE_ENABLE,
|
|
memAWriteHalfWord => MEM_WRITE_HWORD_ENABLE,
|
|
memAWrite => MEM_DATA_WRITE,
|
|
memARead => BRAM_DATA_READ
|
|
);
|
|
end generate;
|
|
|
|
-- Evo RAM, a seperate block of RAM created in BRAM in addition to the main system BRAM, generally used for applications and termed RAM in this module.
|
|
ZPURAMEVO : if (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and SOC_IMPL_RAM = true generate
|
|
ZPURAM : entity work.SinglePortBRAM
|
|
generic map (
|
|
addrbits => SOC_MAX_ADDR_RAM_BIT
|
|
)
|
|
port map (
|
|
clk => SYSCLK,
|
|
memAAddr => MEM_ADDR(ADDR_BIT_RAM_RANGE),
|
|
memAWriteEnable => RAM_WREN,
|
|
memAWriteByte => MEM_WRITE_BYTE_ENABLE,
|
|
memAWriteHalfWord => MEM_WRITE_HWORD_ENABLE,
|
|
memAWrite => MEM_DATA_WRITE,
|
|
memARead => RAM_DATA_READ
|
|
);
|
|
|
|
-- RAM Range SOC_ADDR_RAM_START) -> SOC_ADDR_RAM_END
|
|
RAM_SELECT <= '1' when (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and (MEM_ADDR >= std_logic_vector(to_unsigned(SOC_ADDR_RAM_START, MEM_ADDR'LENGTH)) and MEM_ADDR < std_logic_vector(to_unsigned(SOC_ADDR_RAM_END, MEM_ADDR'LENGTH)))
|
|
else '0';
|
|
|
|
-- Enable write to RAM when selected and CPU in write state.
|
|
RAM_WREN <= '1' when RAM_SELECT = '1' and MEM_WRITE_ENABLE = '1'
|
|
else
|
|
'0';
|
|
end generate;
|
|
|
|
-- SDRAM over System bus.
|
|
ZPUSDRAMEVO : if (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and SOC_IMPL_SDRAM = true and (BOARD_QMV = true or BOARD_CYC1000 = true) generate
|
|
|
|
ZPUSDRAM : entity work.SDRAM
|
|
generic map (
|
|
SDRAM_ROWS => SOC_SDRAM_ROWS, -- Number of Rows in the SDRAM.
|
|
SDRAM_COLUMNS => SOC_SDRAM_COLUMNS, -- Number of Columns in an SDRAM page (ie. 1 row).
|
|
SDRAM_BANKS => SOC_SDRAM_BANKS, -- Number of banks in the SDRAM.
|
|
SDRAM_DATAWIDTH => SOC_SDRAM_DATAWIDTH, -- Data width of SDRAM chip (ie. 16, 32).
|
|
SDRAM_CLK_FREQ => SOC_SDRAM_CLK_FREQ, -- Frequency of SDRAM clock in Hertz.
|
|
SDRAM_tRCD => SOC_SDRAM_tRCD, -- tRCD - RAS to CAS minimum period (in ns), ie. 20ns -> 2 cycles@100MHz
|
|
SDRAM_tRP => SOC_SDRAM_tRP, -- tRP - Precharge delay, min time for a precharge command to complete (in ns), ie. 15ns -> 2 cycles@100MHz
|
|
SDRAM_tRFC => SOC_SDRAM_tRFC, -- tRFC - Auto-refresh minimum time to complete (in ns), ie. 66ns
|
|
SDRAM_tREF => SOC_SDRAM_tREF -- tREF - period of time a complete refresh of all rows is made within (in ms).
|
|
)
|
|
port map (
|
|
-- SDRAM Interface
|
|
SDRAM_CLK => MEMCLK, -- sdram clock running at an offset from system clock.
|
|
SDRAM_RST => not RESET_n, -- reset the sdram controller.
|
|
SDRAM_CKE => SDRAM_CKE, -- clock enable.
|
|
SDRAM_DQ => SDRAM_DQ, -- 16 bit bidirectional data bus
|
|
SDRAM_ADDR => SDRAM_ADDR, -- 12 bit multiplexed address bus
|
|
SDRAM_DQM => SDRAM_DQM, -- two byte masks
|
|
SDRAM_BA => SDRAM_BA, -- two banks
|
|
SDRAM_CS_n => SDRAM_CS_n, -- a single chip select
|
|
SDRAM_WE_n => SDRAM_WE_n, -- write enable
|
|
SDRAM_RAS_n => SDRAM_RAS_n, -- row address select
|
|
SDRAM_CAS_n => SDRAM_CAS_n, -- columns address select
|
|
SDRAM_READY => SDRAM_READY, -- sd ready.
|
|
|
|
-- CPU Interface
|
|
CLK => SYSCLK, -- System master clock
|
|
RESET => not RESET_n, -- high active sync reset
|
|
ADDR => MEM_ADDR(ADDR_BIT_SDRAM_RANGE),
|
|
DATA_IN => MEM_DATA_WRITE, -- write data
|
|
DATA_OUT => SDRAM_DATA_READ, -- read data
|
|
WRITE_BYTE => MEM_WRITE_BYTE_ENABLE, -- Write a single byte.
|
|
WRITE_HWORD => MEM_WRITE_HWORD_ENABLE, -- Write a 16 bit word.
|
|
CS => SDRAM_SELECT, -- Chip Select.
|
|
WREN => SDRAM_WREN, -- Write enable.
|
|
RDEN => SDRAM_RDEN, -- Read enable.
|
|
BUSY => SDRAM_MEM_BUSY
|
|
);
|
|
|
|
---- Replace the SDRAM with a block of BRAM over WishBone, primarily used for testing.
|
|
--ZPUSDRAM : entity work.SinglePortBRAM
|
|
--generic map (
|
|
-- addrbits => 4
|
|
--)
|
|
--port map (
|
|
-- clk => SYSCLK,
|
|
-- memAAddr => MEM_ADDR(3 downto 0),
|
|
-- memAWriteEnable => SDRAM_WREN,
|
|
-- memAWriteByte => MEM_WRITE_BYTE_ENABLE,
|
|
-- memAWriteHalfWord => MEM_WRITE_HWORD_ENABLE,
|
|
-- memAWrite => MEM_DATA_WRITE,
|
|
-- memARead => SDRAM_DATA_READ
|
|
--);
|
|
|
|
-- SDRAM clock based on system clock.
|
|
SDRAM_CLK <= MEMCLK;
|
|
|
|
-- RAM Range SOC_ADDR_SDRAM_START) -> SOC_ADDR_SDRAM_END
|
|
SDRAM_SELECT <= '1' when (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and (MEM_ADDR >= std_logic_vector(to_unsigned(SOC_ADDR_SDRAM_START, MEM_ADDR'LENGTH)) and MEM_ADDR < std_logic_vector(to_unsigned(SOC_ADDR_SDRAM_END, MEM_ADDR'LENGTH)))
|
|
else '0';
|
|
|
|
-- Enable write to RAM when selected and CPU in write state.
|
|
SDRAM_WREN <= '1' when SDRAM_SELECT = '1' and MEM_WRITE_ENABLE = '1'
|
|
else '0';
|
|
SDRAM_RDEN <= '1' when SDRAM_SELECT = '1' and MEM_READ_ENABLE = '1'
|
|
else '0';
|
|
end generate;
|
|
|
|
-- Force the CPU to wait when slower memory/IO is accessed and it cant deliver an immediate result.
|
|
MEM_BUSY <= '1' when (UART0_CS = '1' or UART1_CS = '1' or TIMER0_CS = '1') and MEM_READ_ENABLE = '1'
|
|
else
|
|
'1' when SOC_IMPL_SDRAM = true and (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and (BOARD_QMV = true or BOARD_CYC1000 = true) and SDRAM_MEM_BUSY = '1'
|
|
else
|
|
-- '1' when BRAM_SELECT = '1' and (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and (MEM_READ_ENABLE = '1')
|
|
-- else
|
|
-- '1' when IO_SELECT = '1' and (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and (MEM_READ_ENABLE = '1')
|
|
-- else
|
|
'1' when SOC_IMPL_SD = true and SD_CS = '1' and MEM_READ_ENABLE = '1'
|
|
else
|
|
-- '1' when SOC_IMPL_SPI = true and SPI_CS = '1' and MEM_READ_ENABLE = '1' and IO_WAIT_SPI = '1'
|
|
-- else
|
|
-- '1' when SOC_IMPL_PS2 = true and PS2_CS = '1' and MEM_READ_ENABLE = '1' and IO_WAIT_PS2 = '1'
|
|
-- else
|
|
'1' when SOC_IMPL_INTRCTL = true and INTR0_CS = '1' and MEM_READ_ENABLE = '1' and IO_WAIT_INTR = '1'
|
|
else
|
|
'1' when SOC_IMPL_TIMER1 = true and TIMER1_CS = '1' and MEM_READ_ENABLE = '1' and IO_WAIT_TIMER1 = '1'
|
|
else
|
|
'1' when SOC_IMPL_SOCCFG = true and SOCCFG_CS = '1' and MEM_READ_ENABLE = '1'
|
|
else
|
|
-- '1' when SOC_IMPL_TCPU = true and TCPU_CS = '1'
|
|
'0';
|
|
|
|
-- Select CPU input source, memory or IO.
|
|
MEM_DATA_READ <= BRAM_DATA_READ when BRAM_SELECT = '1'
|
|
else
|
|
RAM_DATA_READ when SOC_IMPL_RAM = true and RAM_SELECT = '1'
|
|
else
|
|
SDRAM_DATA_READ when SOC_IMPL_SDRAM = true and (BOARD_QMV = true or BOARD_CYC1000 = true) and SDRAM_SELECT = '1'
|
|
else
|
|
IO_DATA_READ_SD when SOC_IMPL_SD = true and SD_CS = '1'
|
|
else
|
|
-- IO_DATA_READ_SPI when SOC_IMPL_SPI = true and SPI0_CS = '1'
|
|
-- else
|
|
-- IO_DATA_READ_PS2 when SOC_IMPL_PS2 = true and PS2_CS = '1'
|
|
-- else
|
|
IO_DATA_READ_INTRCTL when SOC_IMPL_INTRCTL = true and INTR0_CS = '1'
|
|
else
|
|
IO_DATA_READ_SOCCFG when SOC_IMPL_SOCCFG = true and SOCCFG_CS = '1'
|
|
else
|
|
IO_DATA_READ_TCPU when SOC_IMPL_TCPU = true and (BOARD_CYC1000 = true) and TCPU_CS = '1'
|
|
else
|
|
IO_DATA_READ when IO_SELECT = '1'
|
|
else
|
|
(others => '1');
|
|
|
|
-- If the wishbone interface is implemented, generate the control and decode logic.
|
|
WISHBONE_CTRL: if SOC_IMPL_WB = true generate
|
|
WB_DAT_I <= WB_DATA_READ_SDRAM when (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and SOC_IMPL_WB_SDRAM = true and WB_SDRAM_STB = '1'
|
|
else
|
|
-- X"000000" & WB_DATA_READ_I2C(BYTE_RANGE) when SOC_IMPL_WB_I2C = true and WB_I2C_CS = '1'
|
|
-- else
|
|
(others => '0');
|
|
|
|
-- Acknowledge is a chain of all enabled device acknowledges as only the addressed device in any given occasion should generate an ACK.
|
|
WB_ACK_I <= WB_SDRAM_ACK when SOC_IMPL_WB_SDRAM = true and WB_SDRAM_STB = '1'
|
|
-- else
|
|
-- WB_I2C_ACK when SOC_IMPL_WB_I2C = true and WB_I2C_CS = '1'
|
|
-- access to an unimplemented area of memory, just ACK as there is nothing to handle the request.
|
|
else '1';
|
|
|
|
-- Halt/Wait signal is a chain of all enabled devices requiring additional bus transaction time.
|
|
WB_HALT_I <= '0'; -- WB_I2C_HALT when SOC_IMPL_WB_I2C = true and WB_I2C_HALT = '1'
|
|
|
|
|
|
-- Error signal is a chain of all enabled device error condition signals.
|
|
WB_ERR_I <= '0'; -- WB_I2C_ERR when SOC_IMPL_WB_I2C = true and WB_I2C_ERR = '1'
|
|
|
|
|
|
-- Interrupt signals are chained with the actual interrupt being stored in the main interrupt controller.
|
|
WB_INTA_I <= '0'; -- WB_I2C_IRQ when SOC_IMPL_WB_I2C = true and WB_I2C_IRQ = '1'
|
|
|
|
|
|
-- Like direct I/O, place peripherals in upper range of wishbone address space.
|
|
WB_IO_SELECT <= '1' when (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and WB_STB_O = '1' and (WB_ADR_O >= std_logic_vector(to_unsigned(SOC_WB_IO_START, WB_ADR_O'LENGTH)) and WB_ADR_O < std_logic_vector(to_unsigned(SOC_WB_IO_END, WB_ADR_O'LENGTH)))
|
|
else '0';
|
|
|
|
WB_IO_SOC_SELECT <= WB_IO_SELECT when WB_ADR_O(19 downto 12) = X"00"
|
|
else '0';
|
|
|
|
-- WB_I2C_CS <= '1' when WB_IO_SOC_SELECT = '1' and WB_ADR_O(11 downto 8) = "0000" -- I2C Range 0x<msb=1>F000xx
|
|
-- else '0';
|
|
|
|
WB_CLK_I <= SYSCLK;
|
|
|
|
else generate
|
|
WB_DAT_I <= (others => '0');
|
|
WB_ACK_I <= '0';
|
|
WB_HALT_I <= '0';
|
|
WB_ERR_I <= '0';
|
|
end generate;
|
|
|
|
-- Enable write to System BRAM when selected and CPU in write state.
|
|
BRAM_WREN <= '1' when (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and MEM_WRITE_ENABLE = '1' and (MEM_ADDR >= std_logic_vector(to_unsigned(SOC_ADDR_BRAM_START, MEM_ADDR'LENGTH)) and MEM_ADDR <= std_logic_vector(to_unsigned(SOC_ADDR_BRAM_END, MEM_ADDR'LENGTH)))
|
|
else
|
|
'1' when ZPU_MEDIUM = 1 and MEM_WRITE_ENABLE = '1' and MEM_ADDR(ioBit) = '0'
|
|
else
|
|
'0';
|
|
|
|
-- -- Were not interested in the mouse, so pass through connection.
|
|
-- PS2M_CLK_OUT <= PS2M_CLK_IN;
|
|
-- PS2M_DAT_OUT <= PS2M_DAT_IN;
|
|
|
|
-- Fixed peripheral Decoding.
|
|
-- BRAM Range 0x00000000 - (2^SOC_MAX_ADDR_INSN_BRAM_BIT)-1
|
|
BRAM_SELECT <= '1' when (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and (MEM_ADDR >= std_logic_vector(to_unsigned(SOC_ADDR_BRAM_START, MEM_ADDR'LENGTH)) and MEM_ADDR < std_logic_vector(to_unsigned(SOC_ADDR_BRAM_END, MEM_ADDR'LENGTH)))
|
|
else
|
|
'1' when (ZPU_MEDIUM = 1 or ZPU_FLEX = 1 or ZPU_SMALL = 1) and MEM_ADDR(ioBit) = '0'
|
|
else '0';
|
|
-- IO Range for EVO CPU
|
|
IO_SELECT <= '1' when (ZPU_SMALL = 1 or ZPU_MEDIUM = 1 or ZPU_FLEX = 1) and MEM_ADDR(ioBit) = '1' -- IO Range for Small, Medium and Flex CPU
|
|
else
|
|
-- '1' when (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and MEM_ADDR(IO_DECODE_RANGE) = std_logic_vector(to_unsigned(255, maxAddrBit - maxIOBit)) and MEM_ADDR(maxIOBit -1 downto 12) = std_logic_vector(to_unsigned(0, maxIOBit-12))
|
|
'1' when (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and ((SOC_IMPL_WB = true and MEM_ADDR(WB_SELECT_BIT) = '0') or SOC_IMPL_WB = false) and MEM_ADDR(IO_DECODE_RANGE) = std_logic_vector(to_unsigned(255, maxAddrBit-WB_ACTIVE - maxIOBit)) and MEM_ADDR(maxIOBit -1 downto 12) = std_logic_vector(to_unsigned(0, maxIOBit-12))
|
|
else '0';
|
|
IO_TIMER_SELECT <= '1' when IO_SELECT = '1' and MEM_ADDR(11 downto 8) = X"C" -- Timer Range 0x<msb=0>FFFFCxx
|
|
else '0';
|
|
UART0_CS <= '1' when IO_SELECT = '1' and MEM_ADDR(11 downto 4) = "10100000" -- Uart Range 0x<msb=0>FFFFAxx, 0xA00-C0F
|
|
else '0';
|
|
UART1_CS <= '1' when IO_SELECT = '1' and MEM_ADDR(11 downto 4) = "10100001" -- Uart Range 0x<msb=0>FFFFAxx, 0xA10-A1F
|
|
else '0';
|
|
TIMER0_CS <= '1' when IO_TIMER_SELECT = '1' and MEM_ADDR(7 downto 6) = "00" -- 0xC00-C3F Millisecond timer.
|
|
else '0';
|
|
SD_CS <= '1' when IO_SELECT = '1' and MEM_ADDR(11 downto 7) = "10010" -- 0x900-90F 0x<msb=0>FFFF9xx, 0x900 - 0x90f First SD Card address range
|
|
else '0';
|
|
|
|
-- Mux the UART debug channel outputs. DBG1 is from the software controlled UART, DBG2 from the cpu channel.
|
|
DEBUGUART: if DEBUG_CPU = true generate
|
|
UART_TX_1 <= UART2_TX;
|
|
else generate
|
|
UART_TX_1 <= UART1_TX;
|
|
end generate;
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Direct Memory I/O devices
|
|
------------------------------------------------------------------------------------
|
|
|
|
TIMER : if SOC_IMPL_TIMER1 = true generate
|
|
-- TIMER
|
|
TIMER1 : entity work.timer_controller
|
|
generic map(
|
|
prescale => 1, -- Prescale incoming clock
|
|
timers => SOC_TIMER1_COUNTERS
|
|
)
|
|
port map (
|
|
clk => SYSCLK,
|
|
reset => RESET_n,
|
|
|
|
reg_addr_in => MEM_ADDR(7 downto 0),
|
|
reg_data_in => MEM_DATA_WRITE,
|
|
reg_rw => '0', -- we never read from the timers
|
|
reg_req => TIMER_REG_REQ,
|
|
|
|
ticks(0) => TIMER1_TICK -- Tick signal is used to trigger an interrupt
|
|
);
|
|
|
|
process(SYSCLK, RESET_n)
|
|
begin
|
|
------------------------
|
|
-- HIGH LEVEL --
|
|
------------------------
|
|
|
|
------------------------
|
|
-- ASYNCHRONOUS RESET --
|
|
------------------------
|
|
if RESET_n='0' then
|
|
TIMER_REG_REQ <= '0';
|
|
IO_WAIT_TIMER1 <= '0';
|
|
|
|
-----------------------
|
|
-- RISING CLOCK EDGE --
|
|
-----------------------
|
|
elsif rising_edge(SYSCLK) then
|
|
|
|
IO_WAIT_TIMER1 <= '0';
|
|
|
|
-- CPU Write?
|
|
if MEM_WRITE_ENABLE = '1' and TIMER1_CS = '1' then
|
|
|
|
-- Write to Timer.
|
|
TIMER_REG_REQ <= '1';
|
|
|
|
-- IO Read?
|
|
elsif MEM_READ_ENABLE = '1' and TIMER1_CS = '1' then
|
|
|
|
end if;
|
|
end if; -- rising-edge(SYSCLK)
|
|
end process;
|
|
|
|
TIMER1_CS <= '1' when IO_TIMER_SELECT = '1' and MEM_ADDR(7 downto 6) = "01" -- 0xC40-C7F
|
|
else '0';
|
|
else generate
|
|
TIMER_REG_REQ <= '0';
|
|
IO_WAIT_TIMER1 <= '0';
|
|
end generate;
|
|
|
|
|
|
-- -- PS2 devices
|
|
-- PS2 : if SOC_IMPL_PS2 = true generate
|
|
-- PS2KEYBOARD : entity work.io_ps2_com
|
|
-- generic map (
|
|
-- clockFilter => 15,
|
|
-- ticksPerUsec => SYSCLK_FREQUENCY/(SYSCLK_FREQUENCY/100)
|
|
-- )
|
|
-- port map (
|
|
-- clk => SYSCLK,
|
|
-- reset => not RESET_n,
|
|
-- ps2_clk_in => PS2K_CLK_IN,
|
|
-- ps2_dat_in => PS2K_DAT_IN,
|
|
-- ps2_clk_out => PS2K_CLK_OUT,
|
|
-- ps2_dat_out => PS2K_DAT_OUT,
|
|
--
|
|
-- inIdle => open,
|
|
-- sendTrigger => KBD_SEND_TRIGGER,
|
|
-- sendByte => KBD_SEND_BYTE,
|
|
-- sendBusy => KBD_SEND_BUSY,
|
|
-- sendDone => KBD_SEND_DONE,
|
|
-- recvTrigger => KBD_RECV,
|
|
-- recvByte => KBD_RECV_BYTE
|
|
-- );
|
|
|
|
-- process(SYSCLK, RESET_n)
|
|
-- begin
|
|
-- ------------------------
|
|
-- -- HIGH LEVEL --
|
|
-- ------------------------
|
|
|
|
-- ------------------------
|
|
-- -- ASYNCHRONOUS RESET --
|
|
-- ------------------------
|
|
-- if RESET_n='0' then
|
|
-- KBD_SEND_TRIGGER <= '0';
|
|
-- KBD_RECV_REG <= '0';
|
|
-- IO_WAIT_PS2 <= '0';
|
|
|
|
-- -----------------------
|
|
-- -- RISING CLOCK EDGE --
|
|
-- -----------------------
|
|
-- elsif rising_edge(SYSCLK) then
|
|
|
|
-- KBD_SEND_TRIGGER <= '0';
|
|
-- IO_WAIT_PS2 <= '0';
|
|
|
|
-- -- CPU Write?
|
|
-- if MEM_WRITE_ENABLE = '1' and PS2_CS = '1' then
|
|
|
|
-- -- Write to PS2 Controller.
|
|
-- KBD_SEND_BYTE <= MEM_DATA_WRITE(7 downto 0);
|
|
-- KBD_SEND_TRIGGER <='1';
|
|
|
|
-- -- IO Read?
|
|
-- elsif MEM_READ_ENABLE = '1' and PS2_CS = '1' then
|
|
|
|
-- -- Read from PS2.
|
|
-- IO_DATA_READ_PS2 <=(others =>'0');
|
|
-- IO_DATA_READ_PS2(11 downto 0) <= KBD_RECV_REG & not KBD_SEND_BUSY & KBD_RECV_BYTE(10 downto 1);
|
|
-- KBD_RECV_REG <='0';
|
|
-- end if;
|
|
|
|
-- -- PS2 interrupt
|
|
-- PS2_INT <= KBD_RECV or KBD_SEND_DONE;
|
|
-- if KBD_RECV='1' then
|
|
-- KBD_RECV_REG <= '1'; -- remains high until cleared by a read
|
|
-- end if;
|
|
|
|
-- end if; -- rising-edge(SYSCLK)
|
|
-- end process;
|
|
|
|
-- PS2_CS <= '1' when IO_SELECT = '1' and MEM_ADDR(11 downto 4) = "11010000" -- PS2 Range 0xFFFFFExx, 0xE00-E0F
|
|
-- else '0';
|
|
-- else generate
|
|
-- PS2_INT <= '0';
|
|
-- PS2_CS <= '0';
|
|
-- KBD_SEND_TRIGGER <= '0';
|
|
-- KBD_RECV_REG <= '0';
|
|
-- IO_WAIT_PS2 <= '0';
|
|
-- end generate;
|
|
|
|
-- -- SPI host
|
|
-- SPI : if SOC_IMPL_SPI = true generate
|
|
|
|
-- SPI0 : entity work.spi_interface
|
|
-- port map(
|
|
-- sysclk => SYSCLK,
|
|
-- reset => RESET_n,
|
|
--
|
|
-- -- Host interface
|
|
-- SPICLK_IN => SPICLK_IN,
|
|
-- HOST_TO_SPI => HOST_TO_SPI,
|
|
-- SPI_TO_HOST => SPI_TO_HOST,
|
|
-- trigger => SPI_TRIGGER,
|
|
-- busy => SPI_BUSY,
|
|
--
|
|
-- -- Hardware interface
|
|
-- miso => SPI_MISO,
|
|
-- mosi => SPI_MOSI,
|
|
-- spiclk_out => SPI_CLK
|
|
-- );
|
|
|
|
-- -- SPI Timer
|
|
-- process(SYSCLK)
|
|
-- begin
|
|
-- if rising_edge(SYSCLK) then
|
|
-- SPICLK_IN <= '0';
|
|
-- SPI_TICK <= SPI_TICK+1;
|
|
-- if (SPI_FAST='1' and SPI_TICK(5)='1') or SPI_TICK(8)='1' then
|
|
-- SPICLK_IN <= '1'; -- Momentary pulse for SPI host.
|
|
-- SPI_TICK <= '0' & X"00";
|
|
-- end if;
|
|
-- end if;
|
|
-- end process;
|
|
|
|
-- process(SYSCLK, RESET_n)
|
|
-- begin
|
|
-- ------------------------
|
|
-- -- HIGH LEVEL --
|
|
-- ------------------------
|
|
|
|
-- ------------------------
|
|
-- -- ASYNCHRONOUS RESET --
|
|
-- ------------------------
|
|
-- if RESET_n='0' then
|
|
-- SPI_CS <= '1';
|
|
-- SPI_ACTIVE <= '0';
|
|
-- IO_WAIT_SPI <= '0';
|
|
--
|
|
-- -----------------------
|
|
-- -- RISING CLOCK EDGE --
|
|
-- -----------------------
|
|
-- elsif rising_edge(SYSCLK) then
|
|
--
|
|
-- SPI_TRIGGER <= '0';
|
|
-- IO_WAIT_SPI <= '0';
|
|
--
|
|
-- -- CPU Write?
|
|
-- if MEM_WRITE_ENABLE = '1' and SPI0_CS = '1' then
|
|
--
|
|
-- -- Write to the SPI.
|
|
-- case MEM_ADDR(3 downto 2) is
|
|
-- when "00" => -- SPI CS
|
|
-- SPI_CS <= not MEM_DATA_WRITE(0);
|
|
-- SPI_FAST <= MEM_DATA_WRITE(8);
|
|
|
|
-- when "01" => -- SPI Data
|
|
-- SPI_WIDE <='0';
|
|
-- SPI_TRIGGER <= '1';
|
|
-- HOST_TO_SPI <= MEM_DATA_WRITE(7 downto 0);
|
|
-- SPI_ACTIVE <= '1';
|
|
-- IO_WAIT_SPI <= '1';
|
|
--
|
|
-- when "10" => -- SPI Pump (32-bit read)
|
|
-- SPI_WIDE <= '1';
|
|
-- SPI_TRIGGER <= '1';
|
|
-- HOST_TO_SPI <= MEM_DATA_WRITE(7 downto 0);
|
|
-- SPI_ACTIVE <= '1';
|
|
-- IO_WAIT_SPI <= '1';
|
|
|
|
-- when others =>
|
|
-- end case;
|
|
--
|
|
-- -- IO Read?
|
|
-- elsif MEM_READ_ENABLE = '1' and SPI0_CS = '1' then
|
|
--
|
|
-- -- Read from SPI.
|
|
-- case MEM_ADDR(3 downto 2) is
|
|
-- when "00" => -- SPI CS
|
|
-- IO_DATA_READ_SPI <= (others =>'X');
|
|
-- IO_DATA_READ_SPI(15) <= SPI_BUSY;
|
|
|
|
-- when "01" => -- SPI Data
|
|
-- SPI_ACTIVE <= '1';
|
|
-- IO_WAIT_SPI <= '1';
|
|
--
|
|
-- when "10" => -- SPI Pump (32-bit read)
|
|
-- SPI_WIDE <= '1';
|
|
-- SPI_TRIGGER <= '1';
|
|
-- SPI_ACTIVE <= '1';
|
|
-- HOST_TO_SPI <= X"FF";
|
|
-- IO_WAIT_SPI <= '1';
|
|
--
|
|
-- when others =>
|
|
-- end case;
|
|
-- end if;
|
|
--
|
|
-- -- SPI cycles
|
|
-- if SPI_ACTIVE='1' then
|
|
-- IO_WAIT_SPI <= SPI_BUSY;
|
|
-- if SPI_BUSY = '0' then
|
|
-- IO_DATA_READ_SPI <= SPI_TO_HOST;
|
|
-- SPI_ACTIVE <= '0';
|
|
-- end if;
|
|
-- end if;
|
|
-- end if; -- rising-edge(SYSCLK)
|
|
-- end process;
|
|
|
|
-- SPI0_CS <= '1' when IO_SELECT = '1' and MEM_ADDR(11 downto 4) = "11010000" -- SPI Range 0xFFFFFDxx, 0xD00-D0F
|
|
-- else '0';
|
|
-- else generate
|
|
-- SPI_CS <= '1';
|
|
-- SPI_ACTIVE <= '0';
|
|
-- IO_WAIT_SPI <= '0';
|
|
-- end generate;
|
|
|
|
|
|
-- SD Card interface. Upto 4 SD Cards can be configured, add an entity for each and set the generics to the values required.
|
|
-- The signals are in the form of an array, so device 0 uses signals in array element 0.
|
|
SDCARD0: if SOC_IMPL_SD = true and SOC_SD_DEVICES >= 1 generate
|
|
|
|
SDCARDS: for I in 0 to SOC_SD_DEVICES-1 generate
|
|
SDCARD : entity work.SDCard
|
|
generic map
|
|
(
|
|
FREQ_G => (Real(SYSCLK_FREQUENCY / 1000000)), -- Master clock frequency (MHz).
|
|
INIT_SPI_FREQ_G => 0.4, -- Slow SPI clock freq. during initialization (MHz).
|
|
SPI_FREQ_G => 25.0, -- Operational SPI freq. to the SD card (MHz).
|
|
BLOCK_SIZE_G => 512 -- Number of bytes in an SD card block or sector.
|
|
)
|
|
port map
|
|
(
|
|
-- Host-side interface signals.
|
|
clk_i => SYSCLK, -- Master clock.
|
|
reset_i => SD_RESET(I), -- active-high, synchronous reset.
|
|
cardtype => SD_CARD_TYPE(I), -- 0 = SD, 1 = SDHC.
|
|
rd_i => SD_RD(I), -- active-high read block request.
|
|
wr_i => SD_WR(I), -- active-high write block request.
|
|
continue_i => SD_CONTINUE(I), -- If true, inc address and continue R/W.
|
|
addr_i => SD_ADDR(I), -- Block address.
|
|
data_i => SD_DATA_WRITE(7 downto 0), -- Data to write to block.
|
|
data_o => SD_DATA_READ(I)(7 downto 0), -- Data read from block.
|
|
busy_o => SD_BUSY(I), -- High when controller is busy performing some operation.
|
|
hndShk_i => SD_HNDSHK_IN(I), -- High when host has data to give or has taken data.
|
|
hndShk_o => SD_HNDSHK_OUT(I), -- High when controller has taken data or has data to give.
|
|
error_o => SD_ERROR(I), -- Card error occurred (1).
|
|
-- I/O signals to the external SD card.
|
|
cs_bo => SDCARD_CS(I), -- Active-low chip-select.
|
|
sclk_o => SDCARD_CLK(I), -- Serial clock to SD card.
|
|
mosi_o => SDCARD_MOSI(I), -- Serial data output to SD card.
|
|
miso_i => SDCARD_MISO(I) -- Serial data input from SD card.
|
|
);
|
|
end generate;
|
|
end generate;
|
|
--
|
|
SDCARDCTL: if SOC_IMPL_SD = true and SOC_SD_DEVICES >= 1 generate
|
|
|
|
process(SYSCLK, RESET_n, MEM_ADDR)
|
|
variable tChannel : integer range 0 to SOC_SD_DEVICES-1;
|
|
begin
|
|
|
|
------------------------
|
|
-- HIGH LEVEL --
|
|
------------------------
|
|
|
|
-- Channel being accessed is in addr bits 5:4.
|
|
tChannel := to_integer(unsigned(MEM_ADDR(6 downto 4)));
|
|
|
|
------------------------
|
|
-- ASYNCHRONOUS RESET --
|
|
------------------------
|
|
if RESET_n='0' then
|
|
SD_ADDR <= (others => (others => DontCareValue));
|
|
SD_RD <= (others => '0');
|
|
SD_WR <= (others => '0');
|
|
SD_RESET <= (others => '0');
|
|
SD_CARD_TYPE <= (others => '0');
|
|
SD_CONTINUE <= (others => '0');
|
|
SD_HNDSHK_IN <= (others => '0');
|
|
SD_OVERRUN <= '0';
|
|
SD_DATA_REQ <= '0';
|
|
SD_DATA_VALID <= '0';
|
|
SD_RESET_TIMER <= 0;
|
|
SD_STATE <= SD_STATE_RESET;
|
|
IO_WAIT_SD <= '0';
|
|
|
|
-----------------------
|
|
-- RISING CLOCK EDGE --
|
|
-----------------------
|
|
elsif rising_edge(SYSCLK) then
|
|
|
|
-- Reset wait state, only 1 cycle long under normal circumstances.
|
|
IO_WAIT_SD <= '0';
|
|
|
|
-- CPU Write?
|
|
if MEM_WRITE_ENABLE = '1' and SD_CS = '1' then
|
|
|
|
-- Write to the SPI.
|
|
case MEM_ADDR(3 downto 2) is
|
|
when "00" => -- Store address for next block operation.
|
|
SD_ADDR(tChannel) <= MEM_DATA_WRITE;
|
|
|
|
-- Write data latch, the host writes data to be written into this register when
|
|
-- the status register SD_DATA_REQ is set.
|
|
when "01" =>
|
|
SD_DATA_WRITE <= MEM_DATA_WRITE(7 downto 0);
|
|
SD_DATA_REQ <= '0';
|
|
|
|
-- Command register, initiate transactions by setting the control bits.
|
|
when "11" => -- Command
|
|
if MEM_DATA_WRITE(0) = '1' then
|
|
SD_STATE <= SD_STATE_RESET;
|
|
elsif MEM_DATA_WRITE(1) = '1' then
|
|
SD_STATE <= SD_STATE_WRITE;
|
|
elsif MEM_DATA_WRITE(2) = '1' then
|
|
SD_STATE <= SD_STATE_READ;
|
|
elsif MEM_DATA_WRITE(3) = '1' then
|
|
SD_CARD_TYPE(tChannel) <= MEM_DATA_WRITE(7);
|
|
end if;
|
|
SD_CHANNEL <= tChannel;
|
|
|
|
when others =>
|
|
end case;
|
|
|
|
-- IO Read?
|
|
elsif MEM_READ_ENABLE = '1' and SD_CS = '1' then
|
|
|
|
-- Read from SPI.
|
|
IO_DATA_READ_SD <= (others => '0');
|
|
case MEM_ADDR(3 downto 2) is
|
|
-- Read back stored address.
|
|
when "00" =>
|
|
IO_DATA_READ_SD <= SD_ADDR(tChannel);
|
|
IO_WAIT_SD <= '0';
|
|
|
|
-- Read Data, only valid if the SD_DATA_VALID bit is set.
|
|
when "01" =>
|
|
IO_WAIT_SD <= '0';
|
|
IO_DATA_READ_SD(31 downto 16) <= SD_ERROR(tChannel);
|
|
IO_DATA_READ_SD(7 downto 0) <= SD_DATA_READ(tChannel);
|
|
SD_DATA_VALID <= '0';
|
|
|
|
-- Card status
|
|
when "11" =>
|
|
IO_DATA_READ_SD(0) <= SD_CONTINUE(tChannel);
|
|
IO_DATA_READ_SD(1) <= SD_BUSY(tChannel);
|
|
IO_DATA_READ_SD(2) <= SD_HNDSHK_OUT(tChannel);
|
|
IO_DATA_READ_SD(3) <= SD_HNDSHK_IN(tChannel);
|
|
IO_DATA_READ_SD(4) <= SD_DATA_REQ; -- 1 when data needed for transmission.
|
|
IO_DATA_READ_SD(5) <= SD_DATA_VALID; -- 1 when data available.
|
|
IO_DATA_READ_SD(6) <= SD_OVERRUN;
|
|
IO_DATA_READ_SD(12 downto 8) <= std_logic_vector(to_unsigned(SDStateType'POS(SD_STATE), 5));
|
|
IO_DATA_READ_SD(13) <= SD_RD(tChannel);
|
|
IO_DATA_READ_SD(14) <= SD_WR(tChannel);
|
|
IO_DATA_READ_SD(15) <= SD_RESET(tChannel);
|
|
IO_DATA_READ_SD(31 downto 16) <= SD_ERROR(tChannel);
|
|
IO_WAIT_SD <= '0';
|
|
SD_OVERRUN <= '0';
|
|
|
|
when others =>
|
|
end case;
|
|
end if;
|
|
|
|
-- State machine to process requests.
|
|
case SD_STATE is
|
|
when SD_STATE_IDLE =>
|
|
SD_RESET <= (others => '0');
|
|
SD_WR <= (others => '0');
|
|
SD_RD <= (others => '0');
|
|
|
|
-----------------------------------------
|
|
-- RESET SD card
|
|
-----------------------------------------
|
|
|
|
-- To reset the card we apply a 100ns reset pulse, the card will then go through the reset procedure, asserting
|
|
-- BUSY until it is ready when BUSY will be deasserted.
|
|
when SD_STATE_RESET =>
|
|
SD_RESET_TIMER <= SYSCLK_FREQUENCY/10000000;
|
|
SD_RESET(SD_CHANNEL) <= '1';
|
|
SD_STATE <= SD_STATE_RESET_1;
|
|
|
|
when SD_STATE_RESET_1 =>
|
|
if SD_RESET_TIMER = 0 then
|
|
SD_RESET(SD_CHANNEL) <= '0';
|
|
SD_STATE <= SD_STATE_IDLE;
|
|
else
|
|
SD_RESET_TIMER <= SD_RESET_TIMER - 1;
|
|
end if;
|
|
|
|
-----------------------------------------
|
|
-- WRITE a sector
|
|
-----------------------------------------
|
|
|
|
-- Address of byte (SD)/block (SDHC) already applied to address input. Set SD_WR high and wait
|
|
-- wait until SD_BUSY goes high.
|
|
when SD_STATE_WRITE =>
|
|
SD_WR(SD_CHANNEL) <= '1';
|
|
SD_DATA_REQ <= '0';
|
|
if SD_BUSY(SD_CHANNEL) = '1' then
|
|
SD_WR(SD_CHANNEL) <= '0';
|
|
SD_STATE <= SD_STATE_WRITE_1;
|
|
end if;
|
|
|
|
-- We now enter a loop, we wait for a byte to be written into the data register, then wait for the controller
|
|
-- to assert HNDSHK_OUT, we raise the handshake line HNDSHK_IN and wait for the deassertion of HNDSHK_OUT to indicate completion.
|
|
-- If SD_BUSY is reset then it indicates completion, either due to an error or because the entire sector was written.
|
|
when SD_STATE_WRITE_1 =>
|
|
-- When DATA Request is clear and the controller starts a handshake, request from the host a byte.
|
|
if SD_DATA_REQ = '0' and SD_HNDSHK_OUT(SD_CHANNEL) = '1' then
|
|
SD_DATA_REQ <= '1';
|
|
SD_STATE <= SD_STATE_WRITE_2;
|
|
|
|
-- If Busy goes inactive then we have completed, either due to an error or completion of the write.
|
|
elsif SD_BUSY(SD_CHANNEL) = '0' then
|
|
SD_STATE <= SD_STATE_IDLE;
|
|
end if;
|
|
|
|
when SD_STATE_WRITE_2 =>
|
|
-- When the data byte is loaded by the host, we raise our handshake line to show data available.
|
|
if SD_DATA_REQ = '0' and SD_HNDSHK_OUT(SD_CHANNEL) = '1' then
|
|
SD_HNDSHK_IN(SD_CHANNEL) <= '1';
|
|
|
|
-- When the controller acknowledges, lower the handshake line to complete the transaction.
|
|
elsif SD_HNDSHK_OUT(SD_CHANNEL) = '0' then
|
|
SD_HNDSHK_IN(SD_CHANNEL) <= '0';
|
|
SD_STATE <= SD_STATE_WRITE_1;
|
|
|
|
elsif SD_BUSY(SD_CHANNEL) = '0' then
|
|
SD_STATE <= SD_STATE_IDLE;
|
|
end if;
|
|
|
|
-----------------------------------------
|
|
-- READ a sector
|
|
-----------------------------------------
|
|
|
|
-- For a read, we raise the SD_RD line and wait for SD_BUSY to go high. Once SD_BUSY is high, SD_RD is deasserted and we
|
|
-- now wait for data.
|
|
when SD_STATE_READ =>
|
|
SD_RD(SD_CHANNEL) <= '1';
|
|
SD_DATA_VALID <= '0';
|
|
if SD_BUSY(SD_CHANNEL) = '1' then
|
|
SD_RD(SD_CHANNEL) <= '0';
|
|
SD_STATE <= SD_STATE_READ_1;
|
|
end if;
|
|
|
|
-- If SD_BUSY is ever deasserted, we are either at the end of a read or an error occurred, in either case exit to IDLE.
|
|
-- We wait for the HNDSHK_OUT to be asserted, read the data, and then move to the next state. In between, if the timeout
|
|
-- timer expires because the controller hasnt sent data, abort as it may have locked up.
|
|
when SD_STATE_READ_1 =>
|
|
|
|
if SD_HNDSHK_OUT(SD_CHANNEL) = '1' then
|
|
SD_DATA_VALID <= '1';
|
|
SD_HNDSHK_IN(SD_CHANNEL) <= '1';
|
|
SD_STATE <= SD_STATE_READ_2;
|
|
|
|
elsif SD_BUSY(SD_CHANNEL) = '0' then
|
|
SD_STATE <= SD_STATE_IDLE;
|
|
|
|
elsif SD_DATA_VALID = '1' and SD_OVERRUN = '0' then
|
|
SD_OVERRUN <= '1';
|
|
end if;
|
|
|
|
-- Wait until the host reads the data, then assert HNDSHK_IN, the controller acknowledges by deasserting HNDSHK_OUT and at this
|
|
-- point the byte read cycle is complete so we deassert HNDSHK_IN. If the timeut expires during this operation or SD_BUSY is
|
|
-- deasserted, exit to IDLE due to error.
|
|
when SD_STATE_READ_2 =>
|
|
|
|
if SD_HNDSHK_OUT(SD_CHANNEL) = '0' and SD_DATA_VALID = '0' then
|
|
SD_HNDSHK_IN(SD_CHANNEL) <= '0';
|
|
SD_STATE <= SD_STATE_READ_1;
|
|
|
|
elsif SD_BUSY(SD_CHANNEL) = '0' then
|
|
SD_STATE <= SD_STATE_IDLE;
|
|
|
|
end if;
|
|
|
|
when others =>
|
|
end case;
|
|
end if;
|
|
end process;
|
|
else generate
|
|
SD_ADDR <= (others => (others => DontCareValue));
|
|
SD_RD <= (others => '0');
|
|
SD_WR <= (others => '0');
|
|
SD_RESET <= (others => '0');
|
|
SD_CARD_TYPE <= (others => '0');
|
|
SD_CONTINUE <= (others => '0');
|
|
SD_HNDSHK_IN <= (others => '0');
|
|
SD_OVERRUN <= '0';
|
|
SD_DATA_REQ <= '0';
|
|
SD_DATA_VALID <= '0';
|
|
SD_RESET_TIMER <= 0;
|
|
SD_STATE <= SD_STATE_RESET;
|
|
IO_WAIT_SD <= '0';
|
|
end generate;
|
|
|
|
-- Interrupt controller
|
|
INTRCTL: if SOC_IMPL_INTRCTL = true generate
|
|
INTCONTROLLER : entity work.interrupt_controller
|
|
generic map (
|
|
max_int => SOC_INTR_MAX
|
|
)
|
|
port map (
|
|
clk => SYSCLK,
|
|
reset_n => RESET_n,
|
|
trigger => INT_TRIGGERS,
|
|
enable_mask => INT_ENABLE,
|
|
ack => INT_DONE,
|
|
int => INT_REQ,
|
|
status => INT_STATUS
|
|
);
|
|
|
|
process(SYSCLK, RESET_n)
|
|
begin
|
|
------------------------
|
|
-- HIGH LEVEL --
|
|
------------------------
|
|
|
|
------------------------
|
|
-- ASYNCHRONOUS RESET --
|
|
------------------------
|
|
if RESET_n='0' then
|
|
INT_ENABLE <= (others => '0');
|
|
IO_WAIT_INTR <= '0';
|
|
IO_DATA_READ_INTRCTL <= (others => 'X');
|
|
|
|
-----------------------
|
|
-- RISING CLOCK EDGE --
|
|
-----------------------
|
|
elsif rising_edge(SYSCLK) then
|
|
|
|
IO_WAIT_INTR <= '0';
|
|
|
|
-- CPU Write?
|
|
if MEM_WRITE_ENABLE = '1' and INTR0_CS = '1' then
|
|
|
|
-- Write to interrupt controller sets the enable mask bits.
|
|
case MEM_ADDR(2) is
|
|
when '0' =>
|
|
|
|
when '1' =>
|
|
INT_ENABLE <= MEM_DATA_WRITE(SOC_INTR_MAX downto 0);
|
|
end case;
|
|
|
|
-- IO Read?
|
|
elsif MEM_READ_ENABLE = '1' and INTR0_CS = '1' then
|
|
|
|
-- Read interrupt status, 32 bits showing which interrupts have been triggered.
|
|
IO_DATA_READ_INTRCTL <= (others => 'X');
|
|
if MEM_ADDR(2) = '0' then
|
|
IO_DATA_READ_INTRCTL(SOC_INTR_MAX downto 0) <= INT_STATUS;
|
|
else
|
|
Io_DATA_READ_INTRCTL(SOC_INTR_MAX downto 0) <= INT_ENABLE;
|
|
end if;
|
|
|
|
end if;
|
|
end if; -- rising-edge(SYSCLK)
|
|
end process;
|
|
|
|
INT_TRIGGERS <= ( 0 => '0',
|
|
1 => MICROSEC_DOWN_INTR,
|
|
2 => MILLISEC_DOWN_INTR,
|
|
3 => SECOND_DOWN_INTR,
|
|
4 => TIMER1_TICK,
|
|
5 => '0', -- PS2_INT
|
|
6 => '0', -- IOCTL_RDINT
|
|
7 => '0', -- IOCTL_WRINT
|
|
8 => UART0_RX_INTR,
|
|
9 => UART0_TX_INTR,
|
|
10 => UART1_RX_INTR,
|
|
11 => UART1_TX_INTR,
|
|
others => '0');
|
|
INT_TRIGGER <= INT_REQ;
|
|
|
|
INTR0_CS <= '1' when IO_SELECT = '1' and MEM_ADDR(11 downto 4) = "10110000" -- Interrupt Range 0xFFFFFBxx, 0xB00-B0F
|
|
else '0';
|
|
|
|
else generate
|
|
IO_DATA_READ_INTRCTL <= (others => 'X');
|
|
INT_TRIGGER <= '0';
|
|
INT_ENABLE <= (others => '0');
|
|
IO_WAIT_INTR <= '0';
|
|
end generate;
|
|
|
|
-- UART
|
|
UART0 : entity work.uart
|
|
generic map (
|
|
RX_FIFO_BIT_DEPTH => MAX_RX_FIFO_BITS,
|
|
TX_FIFO_BIT_DEPTH => MAX_TX_FIFO_BITS,
|
|
COUNTER_BITS => 16,
|
|
BAUDCLK_FREQUENCY => SYSCLK_FREQUENCY
|
|
)
|
|
port map (
|
|
-- CPU Interface
|
|
CLK => SYSCLK, -- memory master clock
|
|
RESET => not RESET_n, -- high active sync reset
|
|
ADDR => MEM_ADDR(3 downto 2), -- 0 = Read/Write Data, 1 = Control Register, 3 = Baud Register
|
|
DATA_IN => MEM_DATA_WRITE, -- write data
|
|
DATA_OUT => UART0_DATA_OUT, -- read data
|
|
CS => UART0_CS, -- Chip Select.
|
|
WREN => MEM_WRITE_ENABLE, -- Write enable.
|
|
RDEN => MEM_READ_ENABLE, -- Read enable.
|
|
|
|
-- IRQ outputs
|
|
TXINTR => UART0_TX_INTR, -- Tx buffer empty interrupt.
|
|
RXINTR => UART0_RX_INTR, -- Rx buffer full interrupt.
|
|
|
|
-- Serial data
|
|
TXD => UART_TX_0,
|
|
RXD => UART_RX_0
|
|
);
|
|
|
|
UART1 : entity work.uart
|
|
generic map (
|
|
RX_FIFO_BIT_DEPTH => MAX_RX_FIFO_BITS,
|
|
TX_FIFO_BIT_DEPTH => MAX_TX_FIFO_BITS,
|
|
COUNTER_BITS => 16,
|
|
BAUDCLK_FREQUENCY => SYSCLK_FREQUENCY
|
|
)
|
|
port map (
|
|
-- CPU Interface
|
|
CLK => SYSCLK, -- memory master clock
|
|
RESET => not RESET_n, -- high active sync reset
|
|
ADDR => MEM_ADDR(3 downto 2), -- 0 = Read/Write Data, 1 = Control Register, 3 = Baud Register
|
|
DATA_IN => MEM_DATA_WRITE, -- write data
|
|
DATA_OUT => UART1_DATA_OUT, -- read data
|
|
CS => UART1_CS, -- Chip Select.
|
|
WREN => MEM_WRITE_ENABLE, -- Write enable.
|
|
RDEN => MEM_READ_ENABLE, -- Read enable.
|
|
|
|
-- IRQ outputs
|
|
TXINTR => UART1_TX_INTR, -- Tx buffer empty interrupt.
|
|
RXINTR => UART1_RX_INTR, -- Rx buffer full interrupt.
|
|
|
|
-- Serial data
|
|
TXD => UART1_TX,
|
|
RXD => UART_RX_1
|
|
);
|
|
|
|
IMPLSOCCFG: if SOC_IMPL_SOCCFG = true generate
|
|
process(SYSCLK, RESET_n)
|
|
begin
|
|
------------------------
|
|
-- HIGH LEVEL --
|
|
------------------------
|
|
|
|
------------------------
|
|
-- ASYNCHRONOUS RESET --
|
|
------------------------
|
|
if RESET_n='0' then
|
|
|
|
-----------------------
|
|
-- RISING CLOCK EDGE --
|
|
-----------------------
|
|
elsif rising_edge(SYSCLK) then
|
|
|
|
-- SoC Configuration.
|
|
IO_DATA_READ_SOCCFG <= (others => 'X');
|
|
case MEM_ADDR(7 downto 2) is
|
|
when "000000" => -- ZPU Id
|
|
IO_DATA_READ_SOCCFG(31 downto 28) <= "1010"; -- Identifier to show SoC Configuration registers are implemented.
|
|
if ZPU_SMALL = 1 then
|
|
IO_DATA_READ_SOCCFG(15 downto 0) <= std_logic_vector(to_unsigned(ZPU_ID_SMALL, 16));
|
|
elsif ZPU_MEDIUM = 1 then
|
|
IO_DATA_READ_SOCCFG(15 downto 0) <= std_logic_vector(to_unsigned(ZPU_ID_MEDIUM, 16));
|
|
elsif ZPU_FLEX = 1 then
|
|
IO_DATA_READ_SOCCFG(15 downto 0) <= std_logic_vector(to_unsigned(ZPU_ID_FLEX, 16));
|
|
elsif ZPU_EVO = 1 then
|
|
IO_DATA_READ_SOCCFG(15 downto 0) <= std_logic_vector(to_unsigned(ZPU_ID_EVO, 16));
|
|
elsif ZPU_EVO_MINIMAL = 1 then
|
|
IO_DATA_READ_SOCCFG(15 downto 0) <= std_logic_vector(to_unsigned(ZPU_ID_EVO_MINIMAL, 16));
|
|
else
|
|
IO_DATA_READ_SOCCFG(15 downto 0) <= (others => '0');
|
|
end if;
|
|
|
|
when "000001" => -- System Frequency
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SYSCLK_FREQUENCY, wordSize));
|
|
|
|
when "000010" => -- Sysbus Memory Frequency
|
|
if (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and SOC_IMPL_SDRAM = true then
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_SDRAM_CLK_FREQ, wordSize));
|
|
else
|
|
IO_DATA_READ_SOCCFG <= (others => 'X');
|
|
end if;
|
|
|
|
when "000011" => -- Wishbone Memory Frequency
|
|
if (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and SOC_IMPL_WB = true and SOC_IMPL_WB_SDRAM = true then
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_WB_SDRAM_CLK_FREQ, wordSize));
|
|
else
|
|
IO_DATA_READ_SOCCFG <= (others => 'X');
|
|
end if;
|
|
|
|
when "000100" => -- Devices Implemented
|
|
IO_DATA_READ_SOCCFG(22 downto 0) <= to_std_logic(SOC_IMPL_WB) &
|
|
to_std_logic(SOC_IMPL_WB_SDRAM) &
|
|
'0' & --to_std_logic(SOC_IMPL_WB_I2C) &
|
|
to_std_logic(SOC_IMPL_BRAM) &
|
|
to_std_logic(SOC_IMPL_RAM) &
|
|
to_std_logic(SOC_IMPL_INSN_BRAM) &
|
|
to_std_logic(SOC_IMPL_SDRAM) &
|
|
'0' & --to_std_logic(SOC_IMPL_IOCTL) &
|
|
'0' & --to_std_logic(SOC_IMPL_PS2) &
|
|
'0' & --to_std_logic(SOC_IMPL_SPI) &
|
|
to_std_logic(SOC_IMPL_SD) &
|
|
std_logic_vector(to_unsigned(SOC_SD_DEVICES, 2)) &
|
|
to_std_logic(SOC_IMPL_INTRCTL) &
|
|
std_logic_vector(to_unsigned(SOC_INTR_MAX, 5)) &
|
|
to_std_logic(SOC_IMPL_TIMER1) &
|
|
std_logic_vector(to_unsigned(2**SOC_TIMER1_COUNTERS, 3));
|
|
|
|
when "000101" => -- BRAM Address
|
|
if SOC_IMPL_BRAM = true then
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_ADDR_BRAM_START, wordSize));
|
|
end if;
|
|
|
|
when "000110" => -- BRAM Size
|
|
if SOC_IMPL_BRAM = true then
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_ADDR_BRAM_END - SOC_ADDR_BRAM_START, wordSize));
|
|
else
|
|
IO_DATA_READ_SOCCFG <= (others => 'X');
|
|
end if;
|
|
|
|
when "000111" => -- RAM Address
|
|
if SOC_IMPL_RAM = true then
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_ADDR_RAM_START, wordSize));
|
|
else
|
|
IO_DATA_READ_SOCCFG <= (others => 'X');
|
|
end if;
|
|
|
|
when "001000" => -- RAM Size
|
|
if SOC_IMPL_RAM = true then
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_ADDR_RAM_END - SOC_ADDR_RAM_START, wordSize));
|
|
else
|
|
IO_DATA_READ_SOCCFG <= (others => 'X');
|
|
end if;
|
|
|
|
when "001001" => -- Instruction BRAM Address
|
|
if SOC_IMPL_INSN_BRAM = true then
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_ADDR_INSN_BRAM_START, wordSize));
|
|
else
|
|
IO_DATA_READ_SOCCFG <= (others => 'X');
|
|
end if;
|
|
|
|
when "001010" => -- Instruction BRAM Size
|
|
if SOC_IMPL_INSN_BRAM = true then
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_ADDR_INSN_BRAM_END - SOC_ADDR_INSN_BRAM_START, wordSize));
|
|
else
|
|
IO_DATA_READ_SOCCFG <= (others => 'X');
|
|
end if;
|
|
|
|
when "001011" => -- SDRAM Address
|
|
if (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and SOC_IMPL_SDRAM = true then
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_ADDR_SDRAM_START, wordSize));
|
|
else
|
|
IO_DATA_READ_SOCCFG <= (others => 'X');
|
|
end if;
|
|
|
|
when "001100" => -- SDRAM Size
|
|
if (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and SOC_IMPL_SDRAM = true then
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_ADDR_SDRAM_END - SOC_ADDR_SDRAM_START, wordSize));
|
|
else
|
|
IO_DATA_READ_SOCCFG <= (others => 'X');
|
|
end if;
|
|
|
|
when "001101" => -- WB SDRAM Address
|
|
if (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and SOC_IMPL_WB = true and SOC_IMPL_WB_SDRAM = true then
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_ADDR_WB_SDRAM_START, wordSize));
|
|
else
|
|
IO_DATA_READ_SOCCFG <= (others => 'X');
|
|
end if;
|
|
|
|
when "001110" => -- WB SDRAM Size
|
|
if (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and SOC_IMPL_WB = true and SOC_IMPL_WB_SDRAM = true then
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_ADDR_WB_SDRAM_END - SOC_ADDR_WB_SDRAM_START, wordSize));
|
|
else
|
|
IO_DATA_READ_SOCCFG <= (others => 'X');
|
|
end if;
|
|
|
|
when "001111" => -- CPU Reset Address
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_RESET_ADDR_CPU, wordSize));
|
|
|
|
when "010000" => -- CPU Memory Start Address
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_START_ADDR_MEM, wordSize));
|
|
|
|
when "010001" => -- Stack Start Address
|
|
IO_DATA_READ_SOCCFG <= std_logic_vector(to_unsigned(SOC_STACK_ADDR, wordSize));
|
|
|
|
when others =>
|
|
end case;
|
|
end if; -- rising-edge(SYSCLK)
|
|
end process;
|
|
|
|
SOCCFG_CS <= '1' when IO_SELECT = '1' and MEM_ADDR(11 downto 8) = "1111" -- SoC Config Range 0xF00-FF0, step 4 for 32 bit registers.
|
|
else '0';
|
|
else generate
|
|
IO_DATA_READ_SOCCFG <= (others => '0');
|
|
end generate;
|
|
|
|
-- TCPU Z80 Bus Controller.
|
|
TCPU0: if (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and SOC_IMPL_TCPU = true generate
|
|
TCPU : entity work.TCPU
|
|
port map (
|
|
-- CPU Interface
|
|
CLK => sysclk, -- memory master clock
|
|
RESET => not RESET_n, -- high active sync reset
|
|
ADDR => MEM_ADDR(4 downto 2),
|
|
DATA_IN => MEM_DATA_WRITE, -- write data
|
|
DATA_OUT => IO_DATA_READ_TCPU,-- read data
|
|
CS => TCPU_CS, -- Chip Select.
|
|
WREN => MEM_WRITE_ENABLE, -- Write enable.
|
|
RDEN => MEM_READ_ENABLE, -- Read enable.
|
|
|
|
-- IRQ outputs
|
|
IRQ_INT_O => open,
|
|
IRQ_NMI_O => open,
|
|
|
|
-- TCPU Bus
|
|
TCPU_DATA => TCPU_DATA, -- Data bus
|
|
TCPU_CTL_SET_n => TCPU_CTL_SET_n, -- Set the transceiver control signals.
|
|
TCPU_CLK_n => TCPU_CLK_n, -- Z80 Main Clock
|
|
TCPU_NMI_n => TCPU_NMI_n, -- Z80 NMI converted to 3.3v
|
|
TCPU_INT_n => TCPU_INT_n, -- Z80 INT converted to 3.,3v
|
|
TCPU_WAIT_I_n => TCPU_WAIT_I_n, -- Z80 Wait converted to 3.3v.
|
|
TCPU_BUSACK_I_n => TCPU_BUSACK_I_n, -- Z80 Bus Ack converted to 3.3v.
|
|
TCPU_BUSACK_n => TCPU_BUSACK_n, -- CYC sending BUS ACK
|
|
TCPU_BUSRQ_n => TCPU_BUSRQ_n, -- CYC requesting Z80 bus.
|
|
TCPU_BUSRQ_I_n => TCPU_BUSRQ_I_n -- System requesting Z80 bus.
|
|
);
|
|
|
|
TCPU_CS <= '1' when IO_SELECT = '1' and MEM_ADDR(11 downto 4) = "01110000" -- Ioctl Range 0xFFFFF7xx 0x700-70F
|
|
else '0';
|
|
end generate;
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- END Direct I/O devices
|
|
------------------------------------------------------------------------------------
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- WISHBONE devices
|
|
------------------------------------------------------------------------------------
|
|
|
|
-- I2C : if (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and EVO_USE_WB_BUS = true and SOC_IMPL_WB_I2C = true generate
|
|
-- I2C_MASTER_0: work.i2c_master_top
|
|
-- generic map (
|
|
-- ARST_LVL => '1' -- asynchronous reset level
|
|
-- )
|
|
-- port map (
|
|
-- -- Wishbone Bus
|
|
-- wb_clk_i => SYSCLK, -- master clock input
|
|
-- wb_rst_i => not RESET_n, -- synchronous active high reset
|
|
-- arst_i => '0', -- asynchronous reset - not used.
|
|
-- wb_adr_i => WB_ADR_O(4 downto 2), -- lower address bits
|
|
-- wb_dat_i => WB_DAT_O(BYTE_RANGE), -- Databus input (lowest 8 bit)
|
|
-- wb_dat_o => WB_DATA_READ_I2C(BYTE_RANGE), -- Databus output
|
|
-- wb_we_i => WB_WE_O, -- Write enable input
|
|
-- wb_stb_i => WB_I2C_CS, -- Strobe signal using chip select.
|
|
-- wb_cyc_i => WB_CYC_O, -- Valid bus cycle input
|
|
-- wb_ack_o => WB_I2C_ACK, -- Bus cycle acknowledge output
|
|
-- wb_inta_o => WB_I2C_IRQ, -- interrupt request output signal
|
|
--
|
|
-- -- I²C lines
|
|
-- scl_pad_i => SCL_PAD_IN, -- i2c clock line input
|
|
-- scl_pad_o => SCL_PAD_OUT, -- i2c clock line output
|
|
-- scl_padoen_o => SCL_PAD_OE, -- i2c clock line output enable, active low
|
|
-- sda_pad_i => SDA_PAD_IN, -- i2c data line input
|
|
-- sda_pad_o => SDA_PAD_OUT, -- i2c data line output
|
|
-- sda_padoen_o => SDA_PAD_OE -- i2c data line output enable, active low
|
|
-- );
|
|
|
|
-- -- Data Width Adaption, I2C is only 8 bits so expand to 32bits.
|
|
-- --WB_DATA_READ_I2C <= x"000000" & I2C_DATA_OUT;
|
|
|
|
-- -- IO Buffer
|
|
-- I2C_SCL_IO <= SCL_PAD_OUT when (SCL_PAD_OE = '0') else 'Z';
|
|
-- I2C_SDA_IO <= SDA_PAD_OUT when (SDA_PAD_OE = '0') else 'Z';
|
|
-- SCL_PAD_IN <= I2C_SCL_IO;
|
|
-- SDA_PAD_IN <= I2C_SDA_IO;
|
|
|
|
-- -- Halt / Error
|
|
-- WB_I2C_HALT <= '0'; -- no throttle -> full speed
|
|
-- WB_I2C_ERR <= '0'; -- nothing can go wrong - never ever!
|
|
-- else generate
|
|
-- I2C_SCL_IO <= 'Z';
|
|
-- I2C_SDA_IO <= 'Z';
|
|
-- SCL_PAD_IN <= 'X';
|
|
-- SDA_PAD_IN <= 'X';
|
|
-- WB_I2C_HALT <= '0';
|
|
-- WB_I2C_ERR <= '0';
|
|
-- end generate;
|
|
|
|
-- SDRAM over WishBone bus.
|
|
ZPUWBSDRAMEVO : if (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and SOC_IMPL_WB = true and SOC_IMPL_WB_SDRAM = true and (BOARD_QMV = true or BOARD_CYC1000 = true) generate
|
|
|
|
ZPUWBSDRAM : entity work.WBSDRAM
|
|
generic map (
|
|
SDRAM_ROWS => SOC_WB_SDRAM_ROWS, -- Number of Rows in the SDRAM.
|
|
SDRAM_COLUMNS => SOC_WB_SDRAM_COLUMNS, -- Number of Columns in an SDRAM page (ie. 1 row).
|
|
SDRAM_BANKS => SOC_WB_SDRAM_BANKS, -- Number of banks in the SDRAM.
|
|
SDRAM_DATAWIDTH => SOC_WB_SDRAM_DATAWIDTH, -- Data width of SDRAM chip (ie. 16, 32).
|
|
SDRAM_CLK_FREQ => SOC_WB_SDRAM_CLK_FREQ, -- Frequency of SDRAM clock in Hertz.
|
|
SDRAM_tRCD => SOC_WB_SDRAM_tRCD, -- tRCD - RAS to CAS minimum period (in ns), ie. 20ns -> 2 cycles@100MHz
|
|
SDRAM_tRP => SOC_WB_SDRAM_tRP, -- tRP - Precharge delay, min time for a precharge command to complete (in ns), ie. 15ns -> 2 cycles@100MHz
|
|
SDRAM_tRFC => SOC_WB_SDRAM_tRFC, -- tRFC - Auto-refresh minimum time to complete (in ns), ie. 66ns
|
|
SDRAM_tREF => SOC_WB_SDRAM_tREF -- tREF - period of time a complete refresh of all rows is made within (in ms).
|
|
)
|
|
port map (
|
|
-- SDRAM Interface
|
|
SDRAM_CLK => MEMCLK, -- sdram clock running at an offset from system clock.
|
|
SDRAM_RST => not RESET_n, -- reset the sdram controller.
|
|
SDRAM_CKE => SDRAM_CKE, -- clock enable.
|
|
SDRAM_DQ => SDRAM_DQ, -- 16 bit bidirectional data bus
|
|
SDRAM_ADDR => SDRAM_ADDR, -- 12 bit multiplexed address bus
|
|
SDRAM_DQM => SDRAM_DQM, -- two byte masks
|
|
SDRAM_BA => SDRAM_BA, -- two banks
|
|
SDRAM_CS_n => SDRAM_CS_n, -- a single chip select
|
|
SDRAM_WE_n => SDRAM_WE_n, -- write enable
|
|
SDRAM_RAS_n => SDRAM_RAS_n, -- row address select
|
|
SDRAM_CAS_n => SDRAM_CAS_n, -- columns address select
|
|
SDRAM_READY => SDRAM_READY, -- sd ready.
|
|
|
|
-- WishBone interface.
|
|
WB_CLK => WB_CLK_I, -- clock to which sdram state machine is synchonized
|
|
WB_RST_I => not RESET_n, -- Reset baased on CPU reset active high.
|
|
WB_DATA_I => WB_DAT_O, -- data input from chipset/cpu
|
|
WB_DATA_O => WB_DATA_READ_SDRAM, -- data output to chipset/cpu
|
|
WB_ACK_O => WB_SDRAM_ACK,
|
|
WB_ADR_I => WB_ADR_O(ADDR_BIT_WB_SDRAM_RANGE), -- lower 2 bits are ignored.
|
|
WB_SEL_I => WB_SEL_O,
|
|
WB_CTI_I => WB_CTI_O, -- cycle type.
|
|
WB_STB_I => WB_SDRAM_STB,
|
|
WB_CYC_I => WB_CYC_O, -- cpu/chipset requests cycle
|
|
WB_WE_I => WB_SDRAM_WREN, -- cpu/chipset requests write
|
|
WB_TGC_I => "0000000", -- cycle tag
|
|
WB_HALT_O => open,
|
|
WB_ERR_O => open
|
|
);
|
|
--
|
|
-- ZPUSRAM: entity work.SRAM
|
|
-- generic map (
|
|
-- addrbits => 14
|
|
-- )
|
|
-- port map (
|
|
-- -- WishBone interface.
|
|
-- WB_CLK_I => WB_CLK_I, -- 100MHz chipset clock to which sdram state machine is synchonized
|
|
-- WB_RST_I => not RESET_n, -- high active sync reset
|
|
-- WB_DATA_I => WB_DAT_O, -- data input from chipset/cpu
|
|
-- WB_DATA_O => WB_DATA_READ_SDRAM, -- data output to chipset/cpu
|
|
-- WB_ACK_O => WB_SDRAM_ACK,
|
|
-- WB_ADR_I => WB_ADR_O(13 downto 0), -- lower 2 bits are ignored.
|
|
-- WB_SEL_I => WB_SEL_O,
|
|
-- WB_CTI_I => WB_CTI_O, -- cycle type.
|
|
-- WB_STB_I => WB_SDRAM_STB,
|
|
-- WB_CYC_I => WB_CYC_O, -- cpu/chipset requests cycle
|
|
-- WB_WE_I => RAM_WREN, -- cpu/chipset requests write
|
|
-- WB_TGC_I => "0000000", -- cycle tag
|
|
-- WB_HALT_O => open,
|
|
-- WB_ERR_O => open
|
|
-- );
|
|
|
|
-- RAM Range SOC_ADDR_RAM_START) -> SOC_ADDR_RAM_END
|
|
WB_SDRAM_SELECT <= '1' when (ZPU_EVO = 1 or ZPU_EVO_MINIMAL = 1) and (WB_ADR_O >= std_logic_vector(to_unsigned(SOC_ADDR_WB_SDRAM_START, WB_ADR_O'LENGTH)) and WB_ADR_O < std_logic_vector(to_unsigned(SOC_ADDR_WB_SDRAM_END, WB_ADR_O'LENGTH)))
|
|
else '0';
|
|
|
|
-- Enable write to RAM when selected and CPU in write state.
|
|
WB_SDRAM_WREN <= '1' when WB_SDRAM_SELECT = '1' and WB_WE_O = '1'
|
|
else
|
|
'0';
|
|
|
|
-- Wishbone strobe based on the RAM Select signal which limits the address range.
|
|
WB_SDRAM_STB <= '1' when WB_SDRAM_SELECT = '1' and WB_STB_O = '1'
|
|
else '0';
|
|
|
|
-- SDRAM clock based on system clock.
|
|
SDRAM_CLK <= MEMCLK;
|
|
else generate
|
|
WB_SDRAM_SELECT <= '0';
|
|
WB_SDRAM_WREN <= '0';
|
|
WB_SDRAM_STB <= '0';
|
|
SDRAM_CLK <= MEMCLK;
|
|
end generate;
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- END WISHBONE devices
|
|
------------------------------------------------------------------------------------
|
|
|
|
|
|
-- Reset counter. Incoming reset toggles reset and holds it low for a fixed period. Additionally, if the primary UART RX receives a break
|
|
-- signal, then the reset is triggered.
|
|
--
|
|
process(SYSCLK, RESET_IN)
|
|
begin
|
|
------------------------
|
|
-- HIGH LEVEL --
|
|
------------------------
|
|
|
|
------------------------
|
|
-- ASYNCHRONOUS RESET --
|
|
------------------------
|
|
if RESET_IN='0' then
|
|
RESET_COUNTER <= X"FFFF";
|
|
RESET_COUNTER_RX <= to_unsigned(((SYSCLK_FREQUENCY)/300), 16);
|
|
RESET_n <= '0';
|
|
|
|
-----------------------
|
|
-- RISING CLOCK EDGE --
|
|
-----------------------
|
|
elsif rising_edge(SYSCLK) then
|
|
|
|
-- If the RX receives a break signal, count down to ensure it is held low for correct period, when the count reaches
|
|
-- zero, start a reset.
|
|
--
|
|
if UART_RX_0 = '0' or UART_RX_1 = '0' then
|
|
RESET_COUNTER_RX <= RESET_COUNTER_RX - 1;
|
|
else
|
|
RESET_COUNTER_RX <= to_unsigned(((SYSCLK_FREQUENCY)/300), 16);
|
|
end if;
|
|
|
|
if RESET_COUNTER_RX = X"0000" then
|
|
RESET_COUNTER <= X"FFFF";
|
|
RESET_COUNTER_RX <= to_unsigned(((SYSCLK_FREQUENCY)/300), 16);
|
|
RESET_n <= '0';
|
|
end if;
|
|
|
|
RESET_COUNTER <= RESET_COUNTER - 1;
|
|
if RESET_COUNTER = X"0000" then
|
|
RESET_n <= '1';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- Main peripheral process, decode address and activate memory/peripheral accordingly.
|
|
process(SYSCLK, RESET_n)
|
|
begin
|
|
------------------------
|
|
-- HIGH LEVEL --
|
|
------------------------
|
|
|
|
------------------------
|
|
-- ASYNCHRONOUS RESET --
|
|
------------------------
|
|
if RESET_n='0' then
|
|
MICROSEC_DOWN_COUNTER <= (others => '0');
|
|
MILLISEC_DOWN_COUNTER <= (others => '0');
|
|
MILLISEC_UP_COUNTER <= (others => '0');
|
|
SECOND_DOWN_COUNTER <= (others => '0');
|
|
MICROSEC_DOWN_TICK <= 0;
|
|
MILLISEC_DOWN_TICK <= 0;
|
|
SECOND_DOWN_TICK <= 0;
|
|
MILLISEC_UP_TICK <= 0;
|
|
MICROSEC_DOWN_INTR <= '0';
|
|
MICROSEC_DOWN_INTR_EN <= '0';
|
|
MILLISEC_DOWN_INTR <= '0';
|
|
MILLISEC_DOWN_INTR_EN <= '0';
|
|
SECOND_DOWN_INTR <= '0';
|
|
SECOND_DOWN_INTR_EN <= '0';
|
|
RTC_MICROSEC_TICK <= 0;
|
|
RTC_MICROSEC_COUNTER <= 0;
|
|
RTC_MILLISEC_COUNTER <= 0;
|
|
RTC_SECOND_COUNTER <= 0;
|
|
RTC_MINUTE_COUNTER <= 0;
|
|
RTC_HOUR_COUNTER <= 0;
|
|
RTC_DAY_COUNTER <= 1;
|
|
RTC_MONTH_COUNTER <= 1;
|
|
RTC_YEAR_COUNTER <= 0;
|
|
RTC_TICK_HALT <= '0';
|
|
|
|
-----------------------
|
|
-- RISING CLOCK EDGE --
|
|
-----------------------
|
|
elsif rising_edge(SYSCLK) then
|
|
|
|
-- CPU Write?
|
|
if MEM_WRITE_ENABLE = '1' and IO_SELECT = '1' then
|
|
|
|
-- Write to Millisecond Timer - set current time and day.
|
|
if TIMER0_CS = '1' then
|
|
case MEM_ADDR(5 downto 2) is
|
|
when "0000" =>
|
|
MICROSEC_DOWN_COUNTER(23 downto 0) <= unsigned(MEM_DATA_WRITE(23 downto 0));
|
|
MICROSEC_DOWN_TICK <= 0;
|
|
|
|
when "0001" =>
|
|
MILLISEC_DOWN_COUNTER(17 downto 0) <= unsigned(MEM_DATA_WRITE(17 downto 0));
|
|
MILLISEC_DOWN_TICK <= 0;
|
|
|
|
when "0010" =>
|
|
MILLISEC_UP_COUNTER(31 downto 0) <= unsigned(MEM_DATA_WRITE(31 downto 0));
|
|
MILLISEC_UP_TICK <= 0;
|
|
|
|
when "0011" =>
|
|
SECOND_DOWN_COUNTER(11 downto 0) <= unsigned(MEM_DATA_WRITE(11 downto 0));
|
|
SECOND_DOWN_TICK <= 0;
|
|
|
|
when "0111" =>
|
|
RTC_TICK_HALT <= MEM_DATA_WRITE(0);
|
|
|
|
when "1000" =>
|
|
RTC_MICROSEC_COUNTER <= to_integer(unsigned(MEM_DATA_WRITE(9 downto 0)));
|
|
RTC_MICROSEC_TICK <= 0;
|
|
|
|
when "1001" =>
|
|
RTC_MILLISEC_COUNTER <= to_integer(unsigned(MEM_DATA_WRITE(9 downto 0)));
|
|
RTC_MICROSEC_TICK <= 0;
|
|
|
|
when "1010" =>
|
|
RTC_SECOND_COUNTER <= to_integer(unsigned(MEM_DATA_WRITE(5 downto 0)));
|
|
RTC_MICROSEC_TICK <= 0;
|
|
|
|
when "1011" =>
|
|
RTC_MINUTE_COUNTER <= to_integer(unsigned(MEM_DATA_WRITE(5 downto 0)));
|
|
RTC_MICROSEC_TICK <= 0;
|
|
|
|
when "1100" =>
|
|
RTC_HOUR_COUNTER <= to_integer(unsigned(MEM_DATA_WRITE(4 downto 0)));
|
|
RTC_MICROSEC_TICK <= 0;
|
|
|
|
when "1101" =>
|
|
RTC_DAY_COUNTER <= to_integer(unsigned(MEM_DATA_WRITE(3 downto 0)));
|
|
RTC_MICROSEC_TICK <= 0;
|
|
|
|
when "1110" =>
|
|
RTC_MONTH_COUNTER <= to_integer(unsigned(MEM_DATA_WRITE(3 downto 0)));
|
|
RTC_MICROSEC_TICK <= 0;
|
|
|
|
when "1111" =>
|
|
RTC_YEAR_COUNTER <= to_integer(unsigned(MEM_DATA_WRITE(11 downto 0)));
|
|
RTC_MICROSEC_TICK <= 0;
|
|
|
|
when others =>
|
|
end case;
|
|
end if;
|
|
end if;
|
|
|
|
-- Read from UART.
|
|
if UART0_CS = '1' then
|
|
IO_DATA_READ <= UART0_DATA_OUT;
|
|
end if;
|
|
if UART1_CS = '1' then
|
|
IO_DATA_READ <= UART1_DATA_OUT;
|
|
end if;
|
|
|
|
-- Read from millisecond timer, read milliseconds in last 24 hours and number of elapsed days.
|
|
if TIMER0_CS = '1' then
|
|
IO_DATA_READ <= (others => '0');
|
|
case MEM_ADDR(5 downto 2) is
|
|
when "0000" =>
|
|
IO_DATA_READ(23 downto 0) <= std_logic_vector(MICROSEC_DOWN_COUNTER(23 downto 0));
|
|
|
|
when "0001" =>
|
|
IO_DATA_READ(17 downto 0) <= std_logic_vector(MILLISEC_DOWN_COUNTER(17 downto 0));
|
|
|
|
when "0010" =>
|
|
IO_DATA_READ(31 downto 0) <= std_logic_vector(MILLISEC_UP_COUNTER(31 downto 0));
|
|
|
|
when "0011" =>
|
|
IO_DATA_READ(11 downto 0) <= std_logic_vector(SECOND_DOWN_COUNTER(11 downto 0));
|
|
|
|
when "1000" =>
|
|
IO_DATA_READ(9 downto 0) <= std_logic_vector(to_unsigned(RTC_MICROSEC_COUNTER, 10));
|
|
|
|
when "1001" =>
|
|
IO_DATA_READ(9 downto 0) <= std_logic_vector(to_unsigned(RTC_MILLISEC_COUNTER, 10));
|
|
|
|
when "1010" =>
|
|
IO_DATA_READ(5 downto 0) <= std_logic_vector(to_unsigned(RTC_SECOND_COUNTER, 6));
|
|
|
|
when "1011" =>
|
|
IO_DATA_READ(5 downto 0) <= std_logic_vector(to_unsigned(RTC_MINUTE_COUNTER, 6));
|
|
|
|
when "1100" =>
|
|
IO_DATA_READ(4 downto 0) <= std_logic_vector(to_unsigned(RTC_HOUR_COUNTER, 5));
|
|
|
|
when "1101" =>
|
|
IO_DATA_READ(4 downto 0) <= std_logic_vector(to_unsigned(RTC_DAY_COUNTER, 5));
|
|
|
|
when "1110" =>
|
|
IO_DATA_READ(3 downto 0) <= std_logic_vector(to_unsigned(RTC_MONTH_COUNTER, 4));
|
|
|
|
when "1111" =>
|
|
IO_DATA_READ(11 downto 0) <= std_logic_vector(to_unsigned(RTC_YEAR_COUNTER, 12));
|
|
|
|
when others =>
|
|
end case;
|
|
end if;
|
|
|
|
-- Timer in microseconds, Each 24 hours the timer is zeroed and the day counter incremented. Used for delay loops
|
|
-- and RTC.
|
|
if RTC_TICK_HALT = '0' then
|
|
RTC_MICROSEC_TICK <= RTC_MICROSEC_TICK+1;
|
|
end if;
|
|
if RTC_MICROSEC_TICK = ((SYSCLK_FREQUENCY/1000000) -1) then -- Sys clock has to be > 1MHz or will not be accurate.
|
|
RTC_MICROSEC_TICK <= 0;
|
|
RTC_MICROSEC_COUNTER <= RTC_MICROSEC_COUNTER + 1;
|
|
|
|
if RTC_MICROSEC_COUNTER = (1000 - 1) then
|
|
RTC_MICROSEC_COUNTER <= 0;
|
|
RTC_MILLISEC_COUNTER <= RTC_MILLISEC_COUNTER + 1;
|
|
|
|
if RTC_MILLISEC_COUNTER = (1000 - 1) then
|
|
RTC_SECOND_COUNTER <= RTC_SECOND_COUNTER + 1;
|
|
RTC_MILLISEC_COUNTER <= 0;
|
|
|
|
if RTC_SECOND_COUNTER = (60 - 1) then
|
|
RTC_MINUTE_COUNTER <= RTC_MINUTE_COUNTER + 1;
|
|
RTC_SECOND_COUNTER <= 0;
|
|
|
|
if RTC_MINUTE_COUNTER = (60 - 1) then
|
|
RTC_HOUR_COUNTER <= RTC_HOUR_COUNTER + 1;
|
|
RTC_MINUTE_COUNTER <= 0;
|
|
|
|
if RTC_HOUR_COUNTER = (24 - 1) then
|
|
RTC_DAY_COUNTER <= RTC_DAY_COUNTER + 1;
|
|
RTC_HOUR_COUNTER <= 0;
|
|
|
|
if (RTC_DAY_COUNTER = 31 and (RTC_MONTH_COUNTER = 4 or RTC_MONTH_COUNTER = 6 or RTC_MONTH_COUNTER = 9 or RTC_MONTH_COUNTER = 11))
|
|
or
|
|
(RTC_DAY_COUNTER = 32 and RTC_MONTH_COUNTER /= 4 and RTC_MONTH_COUNTER /= 6 and RTC_MONTH_COUNTER /= 9 and RTC_MONTH_COUNTER /= 11)
|
|
or
|
|
(RTC_DAY_COUNTER = 29 and RTC_MONTH_COUNTER = 2 and std_logic_vector(to_unsigned(RTC_YEAR_COUNTER, 2)) /= "00")
|
|
or
|
|
(RTC_DAY_COUNTER = 30 and RTC_MONTH_COUNTER = 2 and std_logic_vector(to_unsigned(RTC_YEAR_COUNTER, 2)) = "00")
|
|
then
|
|
RTC_MONTH_COUNTER <= RTC_MONTH_COUNTER + 1;
|
|
RTC_DAY_COUNTER <= 1;
|
|
|
|
if RTC_MONTH_COUNTER = 13 then
|
|
RTC_YEAR_COUNTER <= RTC_YEAR_COUNTER + 1;
|
|
RTC_MONTH_COUNTER <= 1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
-- Down and up counters, each have independent ticks which reset on counter set, this guarantees timer is accurate.
|
|
MICROSEC_DOWN_TICK <= MICROSEC_DOWN_TICK+1;
|
|
if MICROSEC_DOWN_TICK = ((SYSCLK_FREQUENCY/1000000) -1) then -- Sys clock has to be > 1MHz or will not be accurate.
|
|
MICROSEC_DOWN_TICK <= 0;
|
|
|
|
-- Decrement microsecond down counter if not yet zero.
|
|
if MICROSEC_DOWN_COUNTER /= 0 then
|
|
MICROSEC_DOWN_COUNTER <= MICROSEC_DOWN_COUNTER - 1;
|
|
end if;
|
|
if MICROSEC_DOWN_COUNTER = 0 and MICROSEC_DOWN_INTR_EN = '1' then
|
|
MICROSEC_DOWN_INTR <= '1';
|
|
end if;
|
|
end if;
|
|
|
|
MILLISEC_DOWN_TICK <= MILLISEC_DOWN_TICK+1;
|
|
if MILLISEC_DOWN_TICK = (((SYSCLK_FREQUENCY/1000000)*1000) -1) then -- Sys clock has to be > 1MHz or will not be accurate.
|
|
MILLISEC_DOWN_TICK <= 0;
|
|
|
|
-- Decrement millisecond down counter if not yet zero.
|
|
if MILLISEC_DOWN_COUNTER /= 0 then
|
|
MILLISEC_DOWN_COUNTER <= MILLISEC_DOWN_COUNTER - 1;
|
|
end if;
|
|
if MILLISEC_DOWN_COUNTER = 0 and MILLISEC_DOWN_INTR_EN = '1' then
|
|
MILLISEC_DOWN_INTR <= '1';
|
|
end if;
|
|
end if;
|
|
|
|
MILLISEC_UP_TICK <= MILLISEC_UP_TICK+1;
|
|
if MILLISEC_UP_TICK = (((SYSCLK_FREQUENCY/1000000)*1000) - 1) then -- Sys clock has to be > 1MHz or will not be accurate.
|
|
MILLISEC_UP_TICK <= 0;
|
|
MILLISEC_UP_COUNTER <= MILLISEC_UP_COUNTER + 1;
|
|
end if;
|
|
|
|
SECOND_DOWN_TICK <= SECOND_DOWN_TICK+1;
|
|
if SECOND_DOWN_TICK = (((SYSCLK_FREQUENCY/1000000)*1000000) - 1) then -- Sys clock has to be > 1MHz or will not be accurate.
|
|
SECOND_DOWN_TICK <= 0;
|
|
|
|
-- Decrement second down counter if not yet zero.
|
|
if SECOND_DOWN_COUNTER /= 0 then
|
|
SECOND_DOWN_COUNTER <= SECOND_DOWN_COUNTER - 1;
|
|
end if;
|
|
if SECOND_DOWN_COUNTER = 0 and SECOND_DOWN_INTR_EN = '1' then
|
|
SECOND_DOWN_INTR <= '1';
|
|
end if;
|
|
end if;
|
|
end if; -- rising-edge(SYSCLK)
|
|
end process;
|
|
|
|
end architecture;
|