From 8e49e9b08708f1a5a9711e89a9424b4295773225 Mon Sep 17 00:00:00 2001 From: the great greene arkleseizure Date: Sat, 12 Oct 2013 08:17:43 +0100 Subject: fish --- bbc_micro_de1.vhd | 1265 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1265 insertions(+) create mode 100644 bbc_micro_de1.vhd (limited to 'bbc_micro_de1.vhd') 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; -- cgit v1.2.3