aboutsummaryrefslogtreecommitdiffstats
path: root/bbc_micro_de1.vhd
diff options
context:
space:
mode:
Diffstat (limited to 'bbc_micro_de1.vhd')
-rw-r--r--bbc_micro_de1.vhd1265
1 files changed, 1265 insertions, 0 deletions
diff --git a/bbc_micro_de1.vhd b/bbc_micro_de1.vhd
new file mode 100644
index 0000000..e109c36
--- /dev/null
+++ b/bbc_micro_de1.vhd
@@ -0,0 +1,1265 @@
+-- BBC Micro for Altera DE1
+--
+-- Copyright (c) 2011 Mike Stirling
+--
+-- All rights reserved
+--
+-- Redistribution and use in source and synthezised forms, with or without
+-- modification, are permitted provided that the following conditions are met:
+--
+-- * Redistributions of source code must retain the above copyright notice,
+-- this list of conditions and the following disclaimer.
+--
+-- * Redistributions in synthesized form must reproduce the above copyright
+-- notice, this list of conditions and the following disclaimer in the
+-- documentation and/or other materials provided with the distribution.
+--
+-- * Neither the name of the author nor the names of other contributors may
+-- be used to endorse or promote products derived from this software without
+-- specific prior written agreement from the author.
+--
+-- * License is granted for non-commercial use only. A fee may not be charged
+-- for redistributions as source code or in synthesized/hardware form without
+-- specific prior written agreement from the author.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
+-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+-- POSSIBILITY OF SUCH DAMAGE.
+--
+-- BBC B Micro
+--
+-- Terasic DE1 top-level
+--
+-- (C) 2011 Mike Stirling
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+
+-- Generic top-level entity for Altera DE1 board
+entity bbc_micro_de1 is
+generic (
+ -- ROM offset
+ -- The 4MB Flash is used in 16KB banks as a simple mechanism for
+ -- different machines to address different parts of the ROM, saving
+ -- on re-flashing each time a new machine is run on the board.
+ -- This generic sets the upper 8 address bits.
+ -- Note that the lower bits may be ignored by the implementation,
+ -- e.g. where ROMs are bigger than 16K or where multiple banks
+ -- are required. In this case it is important to ensure that the
+ -- ROM images are aligned correctly (such that these ignored bits are 0).
+ --
+ -- For the BBC the ROMs start in bank 8 (the first 8 banks are used by
+ -- the Spectrum project). The particular bank is selected by the sideways
+ -- ROM paging register, and bank 7 is used for the MOS. Recommended layout
+ -- is:
+ --
+ -- 0 Sideways
+ -- 1 Sideways
+ -- 2 Sideways - SuperMMC (DFS)
+ -- 3 Sideways - BASIC
+ -- 4 Not used
+ -- 5 Not used
+ -- 6 Not used
+ -- 7 MOS
+ ROM_OFFSET : std_logic_vector(7 downto 0) := "00001000"
+ );
+port (
+ -- Clocks
+ CLOCK_24 : in std_logic_vector(1 downto 0);
+ CLOCK_27 : in std_logic_vector(1 downto 0);
+ CLOCK_50 : in std_logic;
+ EXT_CLOCK : in std_logic;
+
+ -- Switches
+ SW : in std_logic_vector(9 downto 0);
+ -- Buttons
+ KEY : in std_logic_vector(3 downto 0);
+
+ -- 7 segment displays
+ HEX0 : out std_logic_vector(6 downto 0);
+ HEX1 : out std_logic_vector(6 downto 0);
+ HEX2 : out std_logic_vector(6 downto 0);
+ HEX3 : out std_logic_vector(6 downto 0);
+ -- Red LEDs
+ LEDR : out std_logic_vector(9 downto 0);
+ -- Green LEDs
+ LEDG : out std_logic_vector(7 downto 0);
+
+ -- VGA
+ VGA_R : out std_logic_vector(3 downto 0);
+ VGA_G : out std_logic_vector(3 downto 0);
+ VGA_B : out std_logic_vector(3 downto 0);
+ VGA_HS : out std_logic;
+ VGA_VS : out std_logic;
+
+ -- Serial
+ UART_RXD : in std_logic;
+ UART_TXD : out std_logic;
+
+ -- PS/2 Keyboard
+ PS2_CLK : inout std_logic;
+ PS2_DAT : inout std_logic;
+
+ -- I2C
+ I2C_SCLK : inout std_logic;
+ I2C_SDAT : inout std_logic;
+
+ -- Audio
+ AUD_XCK : out std_logic;
+ AUD_BCLK : out std_logic;
+ AUD_ADCLRCK : out std_logic;
+ AUD_ADCDAT : in std_logic;
+ AUD_DACLRCK : out std_logic;
+ AUD_DACDAT : out std_logic;
+
+ -- SRAM
+ SRAM_ADDR : out std_logic_vector(17 downto 0);
+ SRAM_DQ : inout std_logic_vector(15 downto 0);
+ SRAM_CE_N : out std_logic;
+ SRAM_OE_N : out std_logic;
+ SRAM_WE_N : out std_logic;
+ SRAM_UB_N : out std_logic;
+ SRAM_LB_N : out std_logic;
+
+ -- SDRAM
+ DRAM_ADDR : out std_logic_vector(11 downto 0);
+ DRAM_DQ : inout std_logic_vector(15 downto 0);
+ DRAM_BA_0 : in std_logic;
+ DRAM_BA_1 : in std_logic;
+ DRAM_CAS_N : in std_logic;
+ DRAM_CKE : in std_logic;
+ DRAM_CLK : in std_logic;
+ DRAM_CS_N : in std_logic;
+ DRAM_LDQM : in std_logic;
+ DRAM_RAS_N : in std_logic;
+ DRAM_UDQM : in std_logic;
+ DRAM_WE_N : in std_logic;
+
+ -- Flash
+ FL_ADDR : out std_logic_vector(21 downto 0);
+ FL_DQ : inout std_logic_vector(7 downto 0);
+ FL_RST_N : out std_logic;
+ FL_OE_N : out std_logic;
+ FL_WE_N : out std_logic;
+ FL_CE_N : out std_logic;
+
+ -- SD card (SPI mode)
+ SD_nCS : out std_logic;
+ SD_MOSI : out std_logic;
+ SD_SCLK : out std_logic;
+ SD_MISO : in std_logic;
+
+ -- GPIO
+ GPIO_0 : inout std_logic_vector(35 downto 0);
+ GPIO_1 : inout std_logic_vector(35 downto 0)
+ );
+end entity;
+
+architecture rtl of bbc_micro_de1 is
+
+------------------------------
+-- PLL (32 MHz master clock)
+------------------------------
+
+component pll32 IS
+ PORT
+ (
+ areset : IN STD_LOGIC := '0';
+ inclk0 : IN STD_LOGIC := '0';
+ c0 : OUT STD_LOGIC ;
+ locked : OUT STD_LOGIC
+ );
+end component;
+
+---------
+-- CPU
+---------
+
+component T65 is
+ port(
+ Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816
+ Res_n : in std_logic;
+ Enable : in std_logic;
+ Clk : in std_logic;
+ Rdy : in std_logic;
+ Abort_n : in std_logic;
+ IRQ_n : in std_logic;
+ NMI_n : in std_logic;
+ SO_n : in std_logic;
+ R_W_n : out std_logic;
+ Sync : out std_logic;
+ EF : out std_logic;
+ MF : out std_logic;
+ XF : out std_logic;
+ ML_n : out std_logic;
+ VP_n : out std_logic;
+ VDA : out std_logic;
+ VPA : out std_logic;
+ A : out std_logic_vector(23 downto 0);
+ DI : in std_logic_vector(7 downto 0);
+ DO : out std_logic_vector(7 downto 0)
+ );
+end component;
+
+-----------------
+-- MC6845 CRTC
+-----------------
+
+component mc6845 is
+port (
+ CLOCK : in std_logic;
+ CLKEN : in std_logic;
+ nRESET : in std_logic;
+
+ -- Bus interface
+ ENABLE : in std_logic;
+ R_nW : in std_logic;
+ RS : in std_logic;
+ DI : in std_logic_vector(7 downto 0);
+ DO : out std_logic_vector(7 downto 0);
+
+ -- Display interface
+ VSYNC : out std_logic;
+ HSYNC : out std_logic;
+ DE : out std_logic;
+ CURSOR : out std_logic;
+ LPSTB : in std_logic;
+
+ -- Memory interface
+ MA : out std_logic_vector(13 downto 0);
+ RA : out std_logic_vector(4 downto 0)
+ );
+end component;
+
+-------------------------
+-- "VIDPROC" Video ULA
+-------------------------
+
+component vidproc is
+port (
+ CLOCK : in std_logic;
+ -- Clock enable qualifies display cycles (interleaved with CPU cycles)
+ CLKEN : in std_logic;
+ nRESET : in std_logic;
+
+ -- Clock enable output to CRTC
+ CLKEN_CRTC : out std_logic;
+
+ -- Bus interface
+ ENABLE : in std_logic;
+ A0 : in std_logic;
+ -- CPU data bus (for register writes)
+ DI_CPU : in std_logic_vector(7 downto 0);
+ -- Display RAM data bus (for display data fetch)
+ DI_RAM : in std_logic_vector(7 downto 0);
+
+ -- Control interface
+ nINVERT : in std_logic;
+ DISEN : in std_logic;
+ CURSOR : in std_logic;
+
+ -- Video in (teletext mode)
+ R_IN : in std_logic;
+ G_IN : in std_logic;
+ B_IN : in std_logic;
+
+ -- Video out
+ R : out std_logic;
+ G : out std_logic;
+ B : out std_logic
+ );
+end component;
+
+--------------------------------
+-- SAA5050 Teletext Generator
+--------------------------------
+
+component saa5050 is
+port (
+ CLOCK : in std_logic;
+ -- 6 MHz dot clock enable
+ CLKEN : in std_logic;
+ -- Async reset
+ nRESET : in std_logic;
+
+ -- Character data input (in the bus clock domain)
+ DI_CLOCK : in std_logic;
+ DI_CLKEN : in std_logic;
+ DI : in std_logic_vector(6 downto 0);
+
+ -- Timing inputs
+ -- General line reset (not used)
+ GLR : in std_logic; -- /HSYNC
+ -- Data entry window - high during VSYNC.
+ -- Resets ROM row counter and drives 'flash' signal
+ DEW : in std_logic; -- VSYNC
+ -- Character rounding select - high during even field
+ CRS : in std_logic; -- FIELD
+ -- Load output shift register enable - high during active video
+ LOSE : in std_logic; -- DE
+
+ -- Video out
+ R : out std_logic;
+ G : out std_logic;
+ B : out std_logic;
+ Y : out std_logic
+ );
+end component;
+
+--------------
+-- 6522 VIA
+--------------
+
+component M6522 is
+ port (
+
+ I_RS : in std_logic_vector(3 downto 0);
+ I_DATA : in std_logic_vector(7 downto 0);
+ O_DATA : out std_logic_vector(7 downto 0);
+ O_DATA_OE_L : out std_logic;
+
+ I_RW_L : in std_logic;
+ I_CS1 : in std_logic;
+ I_CS2_L : in std_logic;
+
+ O_IRQ_L : out std_logic; -- note, not open drain
+ -- port a
+ I_CA1 : in std_logic;
+ I_CA2 : in std_logic;
+ O_CA2 : out std_logic;
+ O_CA2_OE_L : out std_logic;
+
+ I_PA : in std_logic_vector(7 downto 0);
+ O_PA : out std_logic_vector(7 downto 0);
+ O_PA_OE_L : out std_logic_vector(7 downto 0);
+
+ -- port b
+ I_CB1 : in std_logic;
+ O_CB1 : out std_logic;
+ O_CB1_OE_L : out std_logic;
+
+ I_CB2 : in std_logic;
+ O_CB2 : out std_logic;
+ O_CB2_OE_L : out std_logic;
+
+ I_PB : in std_logic_vector(7 downto 0);
+ O_PB : out std_logic_vector(7 downto 0);
+ O_PB_OE_L : out std_logic_vector(7 downto 0);
+
+ -- FIXME: Revisit timing in this component. Does it really need a 4x clock?
+ I_P2_H : in std_logic; -- high for phase 2 clock ____----__
+ RESET_L : in std_logic;
+ ENA_4 : in std_logic; -- clk enable (4x system clock rate)
+ CLK : in std_logic
+ );
+end component;
+
+-----------------------------
+-- PS/2 Keyboard Emulation
+-----------------------------
+
+component keyboard is
+port (
+ CLOCK : in std_logic;
+ nRESET : in std_logic;
+ CLKEN_1MHZ : in std_logic;
+
+ -- PS/2 interface
+ PS2_CLK : in std_logic;
+ PS2_DATA : in std_logic;
+
+ -- If 1 then column is incremented automatically at
+ -- 1 MHz rate
+ AUTOSCAN : in std_logic;
+
+ COLUMN : in std_logic_vector(3 downto 0);
+ ROW : in std_logic_vector(2 downto 0);
+
+ -- 1 when currently selected key is down (AUTOSCAN disabled)
+ KEYPRESS : out std_logic;
+ -- 1 when any key is down (except row 0)
+ INT : out std_logic;
+ -- BREAK key output - 1 when pressed
+ BREAK_OUT : out std_logic;
+
+ -- DIP switch inputs
+ DIP_SWITCH : in std_logic_vector(7 downto 0)
+ );
+end component;
+
+-----------------------------
+-- SN76489 sound generator
+-----------------------------
+
+component sn76489_top is
+
+ generic (
+ clock_div_16_g : integer := 1
+ );
+ port (
+ clock_i : in std_logic;
+ clock_en_i : in std_logic;
+ res_n_i : in std_logic;
+ ce_n_i : in std_logic;
+ we_n_i : in std_logic;
+ ready_o : out std_logic;
+ d_i : in std_logic_vector(0 to 7);
+ aout_o : out signed(0 to 7)
+ );
+
+end component;
+
+component i2s_intf is
+generic(
+ mclk_rate : positive := 12000000;
+ sample_rate : positive := 8000;
+ preamble : positive := 1; -- I2S
+ word_length : positive := 16
+ );
+
+port (
+ -- 2x MCLK in (e.g. 24 MHz for WM8731 USB mode)
+ CLK : in std_logic;
+ nRESET : in std_logic;
+
+ -- Parallel IO
+ PCM_INL : out std_logic_vector(word_length - 1 downto 0);
+ PCM_INR : out std_logic_vector(word_length - 1 downto 0);
+ PCM_OUTL : in std_logic_vector(word_length - 1 downto 0);
+ PCM_OUTR : in std_logic_vector(word_length - 1 downto 0);
+
+ -- Codec interface (right justified mode)
+ -- MCLK is generated at half of the CLK input
+ I2S_MCLK : out std_logic;
+ -- LRCLK is equal to the sample rate and is synchronous to
+ -- MCLK. It must be related to MCLK by the oversampling ratio
+ -- given in the codec datasheet.
+ I2S_LRCLK : out std_logic;
+
+ -- Data is shifted out on the falling edge of BCLK, sampled
+ -- on the rising edge. The bit rate is determined such that
+ -- it is fast enough to fit preamble + word_length bits into
+ -- each LRCLK half cycle. The last cycle of each word may be
+ -- stretched to fit to LRCLK. This is OK at least for the
+ -- WM8731 codec.
+ -- The first falling edge of each timeslot is always synchronised
+ -- with the LRCLK edge.
+ I2S_BCLK : out std_logic;
+ -- Output bitstream
+ I2S_DOUT : out std_logic;
+ -- Input bitstream
+ I2S_DIN : in std_logic
+ );
+end component;
+
+component i2c_loader is
+generic (
+ -- Address of slave to be loaded
+ device_address : integer := 16#1a#;
+ -- Number of retries to allow before stopping
+ num_retries : integer := 0;
+ -- Length of clock divider in bits. Resulting bus frequency is
+ -- CLK/2^(log2_divider + 2)
+ log2_divider : integer := 6
+);
+
+port (
+ CLK : in std_logic;
+ nRESET : in std_logic;
+
+ I2C_SCL : inout std_logic;
+ I2C_SDA : inout std_logic;
+
+ IS_DONE : out std_logic;
+ IS_ERROR : out std_logic
+ );
+end component;
+
+component debugger is
+generic (
+ -- Set this for a reasonable half flash duration relative to the
+ -- clock frequency
+ flash_divider : natural := 24
+ );
+port (
+ CLOCK : in std_logic;
+ nRESET : in std_logic;
+ -- CPU clock enable in
+ CLKEN_IN : in std_logic;
+ -- Gated clock enable back out to CPU
+ CLKEN_OUT : out std_logic;
+ -- CPU IRQ in
+ nIRQ_IN : in std_logic;
+ -- Gated IRQ back out to CPU (no interrupts when single stepping)
+ nIRQ_OUT : out std_logic;
+
+ -- CPU
+ A_CPU : in std_logic_vector(15 downto 0);
+ R_nW : in std_logic;
+ SYNC : in std_logic;
+
+ -- Aux bus input for display in hex
+ AUX_BUS : in std_logic_vector(15 downto 0);
+
+ -- Controls
+ -- RUN or HALT CPU
+ RUN : in std_logic;
+ -- Push button to single-step in HALT mode
+ nSTEP : in std_logic;
+ -- Push button to cycle display mode
+ nMODE : in std_logic;
+ -- Push button to cycle display digit in edit mode
+ nDIGIT : in std_logic;
+ -- Push button to cycle digit value in edit mode
+ nSET : in std_logic;
+
+ -- Output to display
+ DIGIT3 : out std_logic_vector(6 downto 0);
+ DIGIT2 : out std_logic_vector(6 downto 0);
+ DIGIT1 : out std_logic_vector(6 downto 0);
+ DIGIT0 : out std_logic_vector(6 downto 0);
+
+ LED_BREAKPOINT : out std_logic;
+ LED_WATCHPOINT : out std_logic
+ );
+end component;
+
+-------------
+-- Signals
+-------------
+
+-- Master clock - 32 MHz
+signal pll_reset : std_logic;
+signal pll_locked : std_logic;
+signal clock : std_logic;
+signal hard_reset_n : std_logic;
+signal reset_n : std_logic;
+
+-- Clock enable counter
+-- CPU and video cycles are interleaved. The CPU runs at 2 MHz (every 16th
+-- cycle) and the video subsystem is enabled on every odd cycle.
+signal clken_counter : unsigned(4 downto 0);
+signal cpu_cycle : std_logic; -- Qualifies all 2 MHz cycles
+signal cpu_cycle_mask : std_logic; -- Set to mask CPU cycles until 1 MHz cycle is complete
+signal cpu_clken : std_logic; -- 2 MHz cycles in which the CPU is enabled
+signal cpu_debug_clken : std_logic; -- CPU clken return from hardware debugger
+-- IO cycles are out of phase with the CPU
+signal vid_clken : std_logic; -- 16 MHz video cycles
+signal mhz4_clken : std_logic; -- Used by 6522
+signal mhz2_clken : std_logic; -- Used for latching CPU address for clock stretch
+signal mhz1_clken : std_logic; -- 1 MHz bus and associated peripherals, 6522 phase 2
+-- SAA5050 needs a 6 MHz clock enable relative to a 24 MHz clock
+signal ttxt_clken_counter : unsigned(1 downto 0);
+signal ttxt_clken : std_logic;
+
+-- Debugger connections
+signal debug_irq_in_n : std_logic;
+signal debug_aux : std_logic_vector(15 downto 0);
+
+-- CPU signals
+signal cpu_mode : std_logic_vector(1 downto 0);
+signal cpu_ready : std_logic;
+signal cpu_abort_n : std_logic;
+signal cpu_irq_n : std_logic;
+signal cpu_nmi_n : std_logic;
+signal cpu_so_n : std_logic;
+signal cpu_r_nw : std_logic;
+signal cpu_sync : std_logic;
+signal cpu_ef : std_logic;
+signal cpu_mf : std_logic;
+signal cpu_xf : std_logic;
+signal cpu_ml_n : std_logic;
+signal cpu_vp_n : std_logic;
+signal cpu_vda : std_logic;
+signal cpu_vpa : std_logic;
+signal cpu_a : std_logic_vector(23 downto 0);
+signal cpu_di : std_logic_vector(7 downto 0);
+signal cpu_do : std_logic_vector(7 downto 0);
+
+-- CRTC signals
+signal crtc_clken : std_logic;
+signal crtc_do : std_logic_vector(7 downto 0);
+signal crtc_vsync : std_logic;
+signal crtc_hsync : std_logic;
+signal crtc_de : std_logic;
+signal crtc_cursor : std_logic;
+signal crtc_lpstb : std_logic := '0';
+signal crtc_ma : std_logic_vector(13 downto 0);
+signal crtc_ra : std_logic_vector(4 downto 0);
+
+-- Decoded display address after address translation for hardware
+-- scrolling
+signal display_a : std_logic_vector(14 downto 0);
+
+-- "VIDPROC" signals
+signal vidproc_invert_n : std_logic;
+signal vidproc_disen : std_logic;
+signal r_in : std_logic;
+signal g_in : std_logic;
+signal b_in : std_logic;
+signal r_out : std_logic;
+signal g_out : std_logic;
+signal b_out : std_logic;
+
+-- SAA5050 signals
+signal ttxt_glr : std_logic;
+signal ttxt_dew : std_logic;
+signal ttxt_crs : std_logic;
+signal ttxt_lose : std_logic;
+signal ttxt_r : std_logic;
+signal ttxt_g : std_logic;
+signal ttxt_b : std_logic;
+signal ttxt_y : std_logic;
+
+-- System VIA signals
+signal sys_via_do : std_logic_vector(7 downto 0);
+signal sys_via_do_oe_n : std_logic;
+signal sys_via_irq_n : std_logic;
+signal sys_via_ca1_in : std_logic := '0';
+signal sys_via_ca2_in : std_logic := '0';
+signal sys_via_ca2_out : std_logic;
+signal sys_via_ca2_oe_n : std_logic;
+signal sys_via_pa_in : std_logic_vector(7 downto 0);
+signal sys_via_pa_out : std_logic_vector(7 downto 0);
+signal sys_via_pa_oe_n : std_logic_vector(7 downto 0);
+signal sys_via_cb1_in : std_logic := '0';
+signal sys_via_cb1_out : std_logic;
+signal sys_via_cb1_oe_n : std_logic;
+signal sys_via_cb2_in : std_logic := '0';
+signal sys_via_cb2_out : std_logic;
+signal sys_via_cb2_oe_n : std_logic;
+signal sys_via_pb_in : std_logic_vector(7 downto 0);
+signal sys_via_pb_out : std_logic_vector(7 downto 0);
+signal sys_via_pb_oe_n : std_logic_vector(7 downto 0);
+
+-- User VIA signals
+signal user_via_do : std_logic_vector(7 downto 0);
+signal user_via_do_oe_n : std_logic;
+signal user_via_irq_n : std_logic;
+signal user_via_ca1_in : std_logic := '0';
+signal user_via_ca2_in : std_logic := '0';
+signal user_via_ca2_out : std_logic;
+signal user_via_ca2_oe_n : std_logic;
+signal user_via_pa_in : std_logic_vector(7 downto 0);
+signal user_via_pa_out : std_logic_vector(7 downto 0);
+signal user_via_pa_oe_n : std_logic_vector(7 downto 0);
+signal user_via_cb1_in : std_logic := '0';
+signal user_via_cb1_out : std_logic;
+signal user_via_cb1_oe_n : std_logic;
+signal user_via_cb2_in : std_logic := '0';
+signal user_via_cb2_out : std_logic;
+signal user_via_cb2_oe_n : std_logic;
+signal user_via_pb_in : std_logic_vector(7 downto 0);
+signal user_via_pb_out : std_logic_vector(7 downto 0);
+signal user_via_pb_oe_n : std_logic_vector(7 downto 0);
+
+-- IC32 latch on System VIA
+signal ic32 : std_logic_vector(7 downto 0);
+signal sound_enable_n : std_logic;
+signal speech_read_n : std_logic;
+signal speech_write_n : std_logic;
+signal keyb_enable_n : std_logic;
+signal disp_addr_offs : std_logic_vector(1 downto 0);
+signal caps_lock_led_n : std_logic;
+signal shift_lock_led_n : std_logic;
+
+-- Keyboard
+signal keyb_column : std_logic_vector(3 downto 0);
+signal keyb_row : std_logic_vector(2 downto 0);
+signal keyb_out : std_logic;
+signal keyb_int : std_logic;
+signal keyb_break : std_logic;
+
+-- Sound generator
+signal sound_ready : std_logic;
+signal sound_di : std_logic_vector(7 downto 0);
+signal sound_ao : signed(7 downto 0);
+signal pcm_inl : std_logic_vector(15 downto 0);
+signal pcm_inr : std_logic_vector(15 downto 0);
+
+-- Memory enables
+signal ram_enable : std_logic; -- 0x0000
+signal rom_enable : std_logic; -- 0x8000 (BASIC/sideways ROMs)
+signal mos_enable : std_logic; -- 0xC000
+-- IO region enables
+signal io_fred : std_logic; -- 0xFC00 (1 MHz bus)
+signal io_jim : std_logic; -- 0xFD00 (1 MHz bus)
+signal io_sheila : std_logic; -- 0xFE00 (System peripherals)
+-- SHIELA
+signal crtc_enable : std_logic; -- 0xFE00-FE07
+signal acia_enable : std_logic; -- 0xFE08-FE0F
+signal serproc_enable : std_logic; -- 0xFE10-FE1F
+signal vidproc_enable : std_logic; -- 0xFE20-FE2F
+signal romsel_enable : std_logic; -- 0xFE30-FE3F
+signal sys_via_enable : std_logic; -- 0xFE40-FE5F
+signal user_via_enable : std_logic; -- 0xFE60-FE7F
+signal fddc_enable : std_logic; -- 0xFE80-FE9F
+signal adlc_enable : std_logic; -- 0xFEA0-FEBF (Econet)
+signal adc_enable : std_logic; -- 0xFEC0-FEDF
+signal tube_enable : std_logic; -- 0xFEE0-FEFF
+
+-- ROM select latch
+signal romsel : std_logic_vector(3 downto 0);
+
+signal mhz1_enable : std_logic; -- Set for access to any 1 MHz peripheral
+
+begin
+ -------------------------
+ -- COMPONENT INSTANCES
+ -------------------------
+
+ -- 32 MHz master clock
+ pll: pll32 port map (
+ pll_reset,
+ CLOCK_24(0),
+ clock,
+ pll_locked );
+
+ -- Hardware debugger block (single-step, breakpoints)
+ debug: debugger port map (
+ clock,
+ hard_reset_n,
+ cpu_clken,
+ cpu_debug_clken,
+ debug_irq_in_n,
+ cpu_irq_n,
+ cpu_a(15 downto 0), cpu_r_nw, cpu_sync,
+ debug_aux,
+ SW(8), -- RUN
+ KEY(3), -- STEP
+ KEY(2), -- MODE
+ KEY(1), -- DIGIT
+ KEY(0), -- SET
+ HEX3, HEX2, HEX1, HEX0,
+ LEDR(3), -- BREAKPOINT
+ LEDR(2) -- WATCHPOINT
+ );
+
+ -- 6502 CPU
+ cpu : T65 port map (
+ cpu_mode,
+ reset_n,
+ cpu_debug_clken,
+ clock,
+ cpu_ready,
+ cpu_abort_n,
+ cpu_irq_n,
+ cpu_nmi_n,
+ cpu_so_n,
+ cpu_r_nw,
+ cpu_sync,
+ cpu_ef,
+ cpu_mf,
+ cpu_xf,
+ cpu_ml_n,
+ cpu_vp_n,
+ cpu_vda,
+ cpu_vpa,
+ cpu_a,
+ cpu_di,
+ cpu_do );
+
+ crtc : mc6845 port map (
+ clock,
+ crtc_clken,
+ reset_n,
+ crtc_enable,
+ cpu_r_nw,
+ cpu_a(0),
+ cpu_do,
+ crtc_do,
+ crtc_vsync,
+ crtc_hsync,
+ crtc_de,
+ crtc_cursor,
+ crtc_lpstb,
+ crtc_ma,
+ crtc_ra );
+
+ video_ula : vidproc port map (
+ clock,
+ vid_clken,
+ reset_n,
+ crtc_clken,
+ vidproc_enable,
+ cpu_a(0),
+ cpu_do,
+ SRAM_DQ(7 downto 0),
+ vidproc_invert_n,
+ vidproc_disen,
+ crtc_cursor,
+ r_in, g_in, b_in,
+ r_out, g_out, b_out
+ );
+
+ teletext : saa5050 port map (
+ CLOCK_24(0), -- This runs at 6 MHz, which we can't derive from the 32 MHz clock
+ ttxt_clken,
+ reset_n,
+ clock, -- Data input is synchronised from the bus clock domain
+ vid_clken,
+ SRAM_DQ(6 downto 0),
+ ttxt_glr,
+ ttxt_dew,
+ ttxt_crs,
+ ttxt_lose,
+ ttxt_r, ttxt_g, ttxt_b, ttxt_y
+ );
+
+ -- System VIA
+ system_via : m6522 port map (
+ cpu_a(3 downto 0),
+ cpu_do,
+ sys_via_do,
+ sys_via_do_oe_n,
+ cpu_r_nw,
+ sys_via_enable,
+ '0', -- nCS2
+ sys_via_irq_n,
+ sys_via_ca1_in,
+ sys_via_ca2_in,
+ sys_via_ca2_out,
+ sys_via_ca2_oe_n,
+ sys_via_pa_in,
+ sys_via_pa_out,
+ sys_via_pa_oe_n,
+ sys_via_cb1_in,
+ sys_via_cb1_out,
+ sys_via_cb1_oe_n,
+ sys_via_cb2_in,
+ sys_via_cb2_out,
+ sys_via_cb2_oe_n,
+ sys_via_pb_in,
+ sys_via_pb_out,
+ sys_via_pb_oe_n,
+ mhz1_clken,
+ hard_reset_n, -- System VIA is reset by power on reset only
+ mhz4_clken,
+ clock
+ );
+
+ -- User VIA
+ user_via : m6522 port map (
+ cpu_a(3 downto 0),
+ cpu_do,
+ user_via_do,
+ user_via_do_oe_n,
+ cpu_r_nw,
+ user_via_enable,
+ '0', -- nCS2
+ user_via_irq_n,
+ user_via_ca1_in,
+ user_via_ca2_in,
+ user_via_ca2_out,
+ user_via_ca2_oe_n,
+ user_via_pa_in,
+ user_via_pa_out,
+ user_via_pa_oe_n,
+ user_via_cb1_in,
+ user_via_cb1_out,
+ user_via_cb1_oe_n,
+ user_via_cb2_in,
+ user_via_cb2_out,
+ user_via_cb2_oe_n,
+ user_via_pb_in,
+ user_via_pb_out,
+ user_via_pb_oe_n,
+ mhz1_clken,
+ reset_n,
+ mhz4_clken,
+ clock
+ );
+
+ -- Keyboard
+ keyb : keyboard port map (
+ clock, hard_reset_n, mhz1_clken,
+ PS2_CLK, PS2_DAT,
+ keyb_enable_n,
+ keyb_column,
+ keyb_row,
+ keyb_out,
+ keyb_int,
+ keyb_break,
+ SW(7 downto 0)
+ );
+
+ -- Sound generator (and drive logic for I2S codec)
+ sound : sn76489_top port map (
+ clock, mhz4_clken,
+ reset_n, '0', sound_enable_n,
+ sound_ready, sound_di,
+ sound_ao
+ );
+ i2s : i2s_intf port map (
+ CLOCK_24(0), reset_n,
+ pcm_inl, pcm_inr,
+ std_logic_vector(sound_ao) & "00000000",
+ std_logic_vector(sound_ao) & "00000000",
+ AUD_XCK, AUD_DACLRCK,
+ AUD_BCLK, AUD_DACDAT, AUD_ADCDAT
+ );
+ i2c : i2c_loader
+ generic map (
+ log2_divider => 7
+ )
+ port map (
+ clock, reset_n,
+ I2C_SCLK, I2C_SDAT,
+ LEDR(5), -- IS_DONE
+ LEDR(4) -- IS_ERROR
+ );
+
+ -- Asynchronous reset
+ -- PLL is reset by external reset switch
+ pll_reset <= not SW(9);
+ -- Keyboard and System VIA are reset by external reset switch or PLL being out of lock
+ hard_reset_n <= not (pll_reset or not pll_locked);
+ -- Rest of system is reset by all of the above plus the keyboard BREAK key
+ reset_n <= hard_reset_n and not keyb_break;
+
+ -- Clock enable generation - 32 MHz clock split into 32 cycles
+ -- CPU is on 0 and 16 (but can be masked by 1 MHz bus accesses)
+ -- Video is on all odd cycles (16 MHz)
+ -- 1 MHz cycles are on cycle 31 (1 MHz)
+ vid_clken <= clken_counter(0); -- 1,3,5...
+ mhz4_clken <= clken_counter(0) and clken_counter(1) and clken_counter(2); -- 7/15/23/31
+ mhz2_clken <= mhz4_clken and clken_counter(3); -- 15/31
+ mhz1_clken <= mhz2_clken and clken_counter(4); -- 31
+ cpu_cycle <= not (clken_counter(0) or clken_counter(1) or clken_counter(2) or clken_counter(3)); -- 0/16
+ cpu_clken <= cpu_cycle and not cpu_cycle_mask;
+
+ clk_gen: process(clock,reset_n)
+ begin
+ if reset_n = '0' then
+ clken_counter <= (others => '0');
+ elsif rising_edge(clock) then
+ clken_counter <= clken_counter + 1;
+ end if;
+ end process;
+
+ cycle_stretch: process(clock,reset_n)
+ begin
+ if reset_n = '0' then
+ cpu_cycle_mask <= '0';
+ elsif rising_edge(clock) and mhz2_clken = '1' then
+ if mhz1_enable = '1' and cpu_cycle_mask = '0' then
+ -- Block CPU cycles until 1 MHz cycle has completed
+ cpu_cycle_mask <= '1';
+ end if;
+ if mhz1_clken = '1' then
+ -- CPU can run again
+ -- FIXME: This may not be correct in terms of CPU cycles, but it
+ -- should work
+ cpu_cycle_mask <= '0';
+ end if;
+ end if;
+ end process;
+
+ ttxt_clk_gen: process(CLOCK_24(0),reset_n)
+ begin
+ if reset_n = '0' then
+ ttxt_clken_counter <= (others => '0');
+ elsif rising_edge(CLOCK_24(0)) then
+ ttxt_clken_counter <= ttxt_clken_counter + 1;
+ end if;
+ end process;
+
+ -- 6 MHz clock enable for SAA5050
+ ttxt_clken <= '1' when ttxt_clken_counter = 0 else '0';
+
+ -- CPU configuration and fixed signals
+ cpu_mode <= "00"; -- 6502
+ cpu_ready <= '1';
+ cpu_abort_n <= '1';
+ cpu_nmi_n <= '1';
+ cpu_so_n <= '1';
+
+ -- Address decoding
+ -- 0x0000 = 32 KB SRAM
+ -- 0x8000 = 16 KB BASIC/Sideways ROMs
+ -- 0xC000 = 16 KB MOS ROM
+ --
+ -- IO regions are mapped into a hole in the MOS. There are three regions:
+ -- 0xFC00 = FRED
+ -- 0xFD00 = JIM
+ -- 0xFE00 = SHEILA
+ ram_enable <= not cpu_a(15);
+ rom_enable <= cpu_a(15) and not cpu_a(14);
+ mos_enable <= cpu_a(15) and cpu_a(14) and not (io_fred or io_jim or io_sheila);
+ io_fred <= '1' when cpu_a(15 downto 8) = "11111100" else '0';
+ io_jim <= '1' when cpu_a(15 downto 8) = "11111101" else '0';
+ io_sheila <= '1' when cpu_a(15 downto 8) = "11111110" else '0';
+ -- The following IO regions are accessed at 1 MHz and hence will stall the
+ -- CPU accordingly
+ mhz1_enable <= io_fred or io_jim or
+ adc_enable or sys_via_enable or user_via_enable or
+ serproc_enable or acia_enable or crtc_enable;
+
+ -- SHEILA address demux
+ -- All the system peripherals are mapped into this page as follows:
+ -- 0xFE00 - 0xFE07 = MC6845 CRTC
+ -- 0xFE08 - 0xFE0F = MC6850 ACIA (Serial/Tape)
+ -- 0xFE10 - 0xFE1F = Serial ULA
+ -- 0xFE20 - 0xFE2F = Video ULA
+ -- 0xFE30 - 0xFE3F = Paged ROM select latch
+ -- 0xFE40 - 0xFE5F = System VIA (6522)
+ -- 0xFE60 - 0xFE7F = User VIA (6522)
+ -- 0xFE80 - 0xFE9F = 8271 Floppy disc controller
+ -- 0xFEA0 - 0xFEBF = 68B54 ADLC for Econet
+ -- 0xFEC0 - 0xFEDF = uPD7002 ADC
+ -- 0xFEE0 - 0xFEFF = Tube ULA
+ process(cpu_a,io_sheila)
+ begin
+ -- All regions normally de-selected
+ crtc_enable <= '0';
+ acia_enable <= '0';
+ serproc_enable <= '0';
+ vidproc_enable <= '0';
+ romsel_enable <= '0';
+ sys_via_enable <= '0';
+ user_via_enable <= '0';
+ fddc_enable <= '0';
+ adlc_enable <= '0';
+ adc_enable <= '0';
+ tube_enable <= '0';
+
+ if io_sheila = '1' then
+ case cpu_a(7 downto 5) is
+ when "000" =>
+ -- 0xFE00
+ if cpu_a(4) = '0' then
+ if cpu_a(3) = '0' then
+ -- 0xFE00
+ crtc_enable <= '1';
+ else
+ -- 0xFE08
+ acia_enable <= '1';
+ end if;
+ else
+ -- 0xFE10
+ serproc_enable <= '1';
+ end if;
+ when "001" =>
+ -- 0xFE20
+ if cpu_a(4) = '0' then
+ -- 0xFE20
+ vidproc_enable <= '1';
+ else
+ -- 0xFE30
+ romsel_enable <= '1';
+ end if;
+ when "010" => sys_via_enable <= '1'; -- 0xFE40
+ when "011" => user_via_enable <= '1'; -- 0xFE60
+ when "100" => fddc_enable <= '1'; -- 0xFE80
+ when "101" => adlc_enable <= '1'; -- 0xFEA0
+ when "110" => adc_enable <= '1'; -- 0xFEC0
+ when "111" => tube_enable <= '1'; -- 0xFEE0
+ when others =>
+ null;
+ end case;
+ end if;
+ end process;
+
+ -- CPU data bus mux and interrupts
+ cpu_di <=
+ SRAM_DQ(7 downto 0) when ram_enable = '1' else
+ FL_DQ when rom_enable = '1' else
+ FL_DQ when mos_enable = '1' else
+ crtc_do when crtc_enable = '1' else
+ "00000010" when acia_enable = '1' else
+ sys_via_do when sys_via_enable = '1' else
+ user_via_do when user_via_enable = '1' else
+ (others => '0'); -- un-decoded locations are pulled down by RP1
+ debug_irq_in_n <= sys_via_irq_n and user_via_irq_n; -- route IRQ through debugger
+ --cpu_irq_n <= sys_via_irq_n and user_via_irq_n;
+
+ -- ROMs are in external flash and split into 16K slots (since this also suits other
+ -- computers that might be run on the same board).
+ -- The first 8 slots are allocated for use here, and the first 4 are decoded as
+ -- the sideways ROMs. Slot 7 is used for the MOS.
+ FL_RST_N <= reset_n;
+ FL_CE_N <= '0';
+ FL_OE_N <= '0';
+ FL_WE_N <= '1';
+ FL_ADDR(21 downto 17) <= ROM_OFFSET(7 downto 3);
+ FL_ADDR(16 downto 14) <=
+ "111" when mos_enable = '1' else
+ "0" & romsel(1 downto 0);
+ FL_ADDR(13 downto 0) <= cpu_a(13 downto 0);
+
+ -- SRAM bus
+ SRAM_UB_N <= '1';
+ SRAM_LB_N <= '0';
+ SRAM_CE_N <= '0';
+ SRAM_OE_N <= '0';
+ SRAM_DQ(15 downto 8) <= (others => '0');
+
+ -- Synchronous outputs to SRAM
+ process(clock,reset_n)
+ variable ram_write : std_logic;
+ begin
+ ram_write := ram_enable and not cpu_r_nw;
+
+ if reset_n = '0' then
+ SRAM_WE_N <= '1';
+ SRAM_DQ(7 downto 0) <= (others => 'Z');
+ elsif rising_edge(clock) then
+ -- Default to inputs
+ SRAM_DQ(7 downto 0) <= (others => 'Z');
+
+ -- Register SRAM signals to outputs (clock must be at least 2x CPU clock)
+ if vid_clken = '1' then
+ -- Fetch data from previous CPU cycle
+ SRAM_WE_N <= not ram_write;
+ SRAM_ADDR <= "00" & cpu_a(15 downto 0);
+ if ram_write = '1' then
+ SRAM_DQ(7 downto 0) <= cpu_do;
+ end if;
+ else
+ -- Fetch data from previous display cycle
+ SRAM_WE_N <= '1';
+ SRAM_ADDR <= "000" & display_a;
+ end if;
+ end if;
+ end process;
+
+ -- Address translation logic for calculation of display address
+ process(crtc_ma,crtc_ra,disp_addr_offs)
+ variable aa : unsigned(3 downto 0);
+ begin
+ if crtc_ma(12) = '0' then
+ -- No adjustment
+ aa := unsigned(crtc_ma(11 downto 8));
+ else
+ -- Address adjusted according to screen mode to compensate for
+ -- wrap at 0x8000.
+ case disp_addr_offs is
+ when "00" =>
+ -- Mode 3 - restart at 0x4000
+ aa := unsigned(crtc_ma(11 downto 8)) + 8;
+ when "01" =>
+ -- Mode 6 - restart at 0x6000
+ aa := unsigned(crtc_ma(11 downto 8)) + 12;
+ when "10" =>
+ -- Mode 0,1,2 - restart at 0x3000
+ aa := unsigned(crtc_ma(11 downto 8)) + 6;
+ when "11" =>
+ -- Mode 4,5 - restart at 0x5800
+ aa := unsigned(crtc_ma(11 downto 8)) + 11;
+ when others =>
+ null;
+ end case;
+ end if;
+
+ if crtc_ma(13) = '0' then
+ -- HI RES
+ display_a <= std_logic_vector(aa(3 downto 0)) & crtc_ma(7 downto 0) & crtc_ra(2 downto 0);
+ else
+ -- TTX VDU
+ display_a <= std_logic(aa(3)) & "1111" & crtc_ma(9 downto 0);
+ end if;
+ end process;
+
+ -- VIDPROC
+ vidproc_invert_n <= '1';
+ vidproc_disen <= crtc_de and not crtc_ra(3); -- DISEN is masked off by RA(3) for MODEs 3 and 6
+ r_in <= ttxt_r;
+ g_in <= ttxt_g;
+ b_in <= ttxt_b;
+
+ -- SAA5050
+ ttxt_glr <= not crtc_hsync;
+ ttxt_dew <= crtc_vsync;
+ ttxt_crs <= not crtc_ra(0);
+ ttxt_lose <= crtc_de;
+
+ -- CRTC drives video out (CSYNC on HSYNC output, VSYNC high)
+ VGA_HS <= not (crtc_hsync xor crtc_vsync);
+ VGA_VS <= '1';
+ VGA_R <= r_out & r_out & r_out & r_out;
+ VGA_G <= g_out & g_out & g_out & g_out;
+ VGA_B <= b_out & b_out & b_out & b_out;
+
+ -- Connections to System VIA
+ -- ADC
+ sys_via_cb1_in <= '1'; -- /EOC
+ -- CRTC
+ sys_via_ca1_in <= crtc_vsync;
+ sys_via_cb2_in <= crtc_lpstb;
+ -- Keyboard
+ sys_via_ca2_in <= keyb_int;
+ sys_via_pa_in(7) <= keyb_out;
+ sys_via_pa_in(6 downto 0) <= sys_via_pa_out(6 downto 0); -- Must loop back output pins or keyboard won't work
+ keyb_column <= sys_via_pa_out(3 downto 0);
+ keyb_row <= sys_via_pa_out(6 downto 4);
+ -- Sound
+ sound_di <= sys_via_pa_out;
+ -- Others (idle until missing bits implemented)
+ sys_via_pb_in(7 downto 4) <= (others => '1');
+
+ -- Connections to User VIA (user port is output on green LEDs)
+ user_via_ca1_in <= '1'; -- Pulled up
+ --LEDG <= user_via_pb_out;
+
+ -- MMBEEB
+ user_via_cb1_in <= user_via_pb_out(1);
+ SD_SCLK <= user_via_pb_out(1); -- SCLK
+ SD_MOSI <= user_via_pb_out(0); -- SDO
+ SD_nCS <= '0'; -- CS
+ user_via_cb2_in <= SD_MISO; -- SDI
+ user_via_pb_in <= user_via_pb_out;
+
+ -- ROM select latch
+ process(clock,reset_n)
+ begin
+ if reset_n = '0' then
+ romsel <= (others => '0');
+ elsif rising_edge(clock) then
+ if romsel_enable = '1' and cpu_r_nw = '0' then
+ romsel <= cpu_do(3 downto 0);
+ end if;
+ end if;
+ end process;
+
+ -- IC32 latch
+ sound_enable_n <= ic32(0);
+ speech_write_n <= ic32(1);
+ speech_read_n <= ic32(2);
+ keyb_enable_n <= ic32(3);
+ disp_addr_offs <= ic32(5 downto 4);
+ caps_lock_led_n <= ic32(6);
+ shift_lock_led_n <= ic32(7);
+
+ process(clock,reset_n)
+ variable bit_num : integer;
+ begin
+ bit_num := to_integer(unsigned(sys_via_pb_out(2 downto 0)));
+
+ if reset_n = '0' then
+ ic32 <= (others => '0');
+ elsif rising_edge(clock) then
+ ic32(bit_num) <= sys_via_pb_out(3);
+ end if;
+ end process;
+
+ -- Keyboard LEDs
+ LEDR(0) <= not caps_lock_led_n;
+ LEDR(1) <= not shift_lock_led_n;
+
+ -----------------
+ -- DEBUG STUFF
+ -----------------
+
+ GPIO_0(0) <= not (crtc_hsync xor crtc_vsync);
+ GPIO_0(1) <= crtc_de;
+
+end architecture;