------------------------------------------------------------------------------- -- -- Top level of an Apple ][+ -- -- Stephen A. Edwards, sedwards@cs.columbia.edu -- ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.T65_Pack.all; entity apple2 is generic ( use_bios_rom : boolean := true; -- use test bios use_auto_rom : boolean := false; -- use apple II roms use_cpu65xx_core : boolean := false; use_T65_core : boolean := true ); port ( CLK_14M : in std_logic; -- 14.31818 MHz master clock CLK_2M : out std_logic; PRE_PHASE_ZERO : out std_logic; FLASH_CLK : in std_logic; -- approx. 2 Hz flashing char clock reset : in std_logic; ADDR : out unsigned(15 downto 0); -- CPU address ram_addr : out unsigned(15 downto 0); -- RAM address D : out unsigned(7 downto 0); -- Data to RAM ram_do : in unsigned(7 downto 0); -- Data from RAM PD : in unsigned(7 downto 0); -- Data to CPU from peripherals ram_we : out std_logic; -- RAM write enable VIDEO : out std_logic; COLOR_LINE : out std_logic; HBL : out std_logic; VBL : out std_logic; LD194 : out std_logic; K : in unsigned(7 downto 0); -- Keyboard data READ_KEY : out std_logic; -- Processor has read key AN : out std_logic_vector(3 downto 0); -- Annunciator outputs -- GAMEPORT input bits: -- 7 6 5 4 3 2 1 0 -- pdl3 pdl2 pdl1 pdl0 pb3 pb2 pb1 casette GAMEPORT : in std_logic_vector(7 downto 0); PDL_STROBE : out std_logic; -- Pulses high when C07x read STB : out std_logic; -- Pulses high when C04x read IO_SELECT : out std_logic_vector(7 downto 0); DEVICE_SELECT : out std_logic_vector(7 downto 0); debugPc : out unsigned(15 downto 0); debugOpcode : out unsigned(7 downto 0); debugA : out unsigned(7 downto 0); debugX : out unsigned(7 downto 0); debugY : out unsigned(7 downto 0); debugS : out unsigned(7 downto 0); speaker : out std_logic -- One-bit speaker output ); end apple2; architecture rtl of apple2 is -- Clocks signal CLK_7M : std_logic; signal Q3, RAS_N, CAS_N, AX : std_logic; signal PHASE_ZERO, PRE_PHASE_ZERO_sig : std_logic; signal COLOR_REF : std_logic; -- From the timing generator signal VIDEO_ADDRESS : unsigned(15 downto 0); signal LDPS_N : std_logic; signal H0, VA, VB, VC, V2, V4 : std_logic; signal BLANK, LD194_I : std_logic; signal HIRES : std_logic; -- from video generator B11 p6 -- Soft switches signal soft_switches : std_logic_vector(7 downto 0) := "00000000"; signal TEXT_MODE : std_logic; signal MIXED_MODE : std_logic; signal PAGE2 : std_logic; signal HIRES_MODE : std_logic; -- CPU signals signal D_IN : unsigned(7 downto 0); signal A : unsigned(15 downto 0); signal A_BIG : unsigned(23 downto 0); signal we : std_logic; signal R_W_n : std_logic; -- Main ROM signals signal rom_out : unsigned(7 downto 0); signal rom_addr : unsigned(13 downto 0); -- Address decoder signals signal RAM_SELECT : std_logic := '1'; signal KEYBOARD_SELECT : std_logic := '0'; signal SPEAKER_SELECT : std_logic; signal SOFTSWITCH_SELECT : std_logic; signal ROM_SELECT : std_logic; signal GAMEPORT_SELECT : std_logic; signal IO_STROBE : std_logic; -- Speaker signal signal speaker_sig : std_logic := '0'; signal DL : unsigned(7 downto 0); -- Latched RAM data signal DEBUG : T_t65_dbg; begin CLK_2M <= Q3; PRE_PHASE_ZERO <= PRE_PHASE_ZERO_sig; ram_addr <= A when PHASE_ZERO = '1' else VIDEO_ADDRESS; ram_we <= we and not RAS_N when PHASE_ZERO = '1' else '0'; -- Latch RAM data on the rising edge of RAS RAM_data_latch : process (CLK_14M) begin if rising_edge(CLK_14M) then if AX = '1' and CAS_N = '0' and RAS_N = '0' then DL <= ram_do; end if; end if; end process; ADDR <= A; -- Address decoding rom_addr <= (A(13) and A(12)) & (not A(12)) & A(11 downto 0); address_decoder: process (A) begin ROM_SELECT <= '0'; RAM_SELECT <= '0'; KEYBOARD_SELECT <= '0'; READ_KEY <= '0'; SPEAKER_SELECT <= '0'; SOFTSWITCH_SELECT <= '0'; GAMEPORT_SELECT <= '0'; PDL_STROBE <= '0'; STB <= '0'; IO_SELECT <= (others => '0'); DEVICE_SELECT <= (others => '0'); IO_STROBE <= '0'; case A(15 downto 14) is when "00" | "01" | "10" => -- 0000 - BFFF RAM_SELECT <= '1'; when "11" => -- C000 - FFFF case A(13 downto 12) is when "00" => -- C000 - CFFF case A(11 downto 8) is when x"0" => -- C000 - C0FF case A(7 downto 4) is when x"0" => -- C000 - C00F KEYBOARD_SELECT <= '1'; when x"1" => -- C010 - C01F READ_KEY <= '1'; when x"3" => -- C030 - C03F SPEAKER_SELECT <= '1'; when x"4" => STB <= '1'; when x"5" => -- C050 - C05F SOFTSWITCH_SELECT <= '1'; when x"6" => -- C060 - C06F GAMEPORT_SELECT <= '1'; when x"7" => -- C070 - C07F PDL_STROBE <= '1'; when x"8" | x"9" | x"A" | -- C080 - C0FF x"B" | x"C" | x"D" | x"E" | x"F" => DEVICE_SELECT(TO_INTEGER(A(6 downto 4))) <= '1'; when others => null; end case; when x"1" | x"2" | x"3" | -- C100 - C7FF x"4" | x"5" | x"6" | x"7" => IO_SELECT(TO_INTEGER(A(10 downto 8))) <= '1'; when x"8" | x"9" | x"A" | -- C800 - CFFF x"B" | x"C" | x"D" | x"E" | x"F" => IO_STROBE <= '1'; when others => null; end case; when "01" | "10" | "11" => -- D000 - FFFF ROM_SELECT <= '1'; when others => null; end case; when others => null; end case; end process address_decoder; speaker_ctrl: process (Q3) begin if rising_edge(Q3) then if PRE_PHASE_ZERO_sig = '1' and SPEAKER_SELECT = '1' then speaker_sig <= not speaker_sig; end if; end if; end process speaker_ctrl; softswitches: process (Q3) begin if rising_edge(Q3) then if PRE_PHASE_ZERO_sig = '1' and SOFTSWITCH_SELECT = '1' then soft_switches(TO_INTEGER(A(3 downto 1))) <= A(0); end if; end if; end process softswitches; TEXT_MODE <= soft_switches(0); MIXED_MODE <= soft_switches(1); PAGE2 <= soft_switches(2); HIRES_MODE <= soft_switches(3); AN <= soft_switches(7 downto 4); speaker <= speaker_sig; D_IN <= DL when RAM_SELECT = '1' else -- RAM K when KEYBOARD_SELECT = '1' else -- Keyboard GAMEPORT(TO_INTEGER(A(2 downto 0))) & "0000000" -- Gameport when GAMEPORT_SELECT = '1' else rom_out when ROM_SELECT = '1' else -- ROMs PD; -- Peripherals LD194 <= LD194_I; timing : entity work.timing_generator port map ( CLK_14M => CLK_14M, CLK_7M_out => CLK_7M, CAS_N_out => CAS_N, RAS_N_out => RAS_N, Q3_out => Q3, AX_out => AX, PHI0_out => PHASE_ZERO, PRE_PHI0_out => PRE_PHASE_ZERO_sig, COLOR_REF_out => COLOR_REF, TEXT_MODE => TEXT_MODE, PAGE2 => PAGE2, HIRES => HIRES, VIDEO_ADDRESS => VIDEO_ADDRESS, H0 => H0, VA => VA, VB => VB, VC => VC, V2 => V2, V4 => V4, VBL_out => VBL, HBL_out => HBL, BLANK => BLANK, LDPS_N => LDPS_N, LD194 => LD194_I); video_display : entity work.video_generator port map ( CLK_14M => CLK_14M, CLK_7M => CLK_7M, AX => AX, CAS_N => CAS_N, TEXT_MODE => TEXT_MODE, PAGE2 => PAGE2, HIRES_MODE => HIRES_MODE, MIXED_MODE => MIXED_MODE, H0 => H0, VA => VA, VB => VB, VC => VC, V2 => V2, V4 => V4, BLANK => BLANK, DL => DL, LDPS_N => LDPS_N, LD194 => LD194_I, FLASH_CLK => FLASH_CLK, HIRES => HIRES, VIDEO => VIDEO, COLOR_LINE => COLOR_LINE); cpu65xx_core: if use_cpu65xx_core generate cpu : entity work.cpu65xx generic map ( pipelineOpcode => false, pipelineAluMux => false, pipelineAluOut => false) port map ( clk => Q3, enable => not PRE_PHASE_ZERO_sig, reset => reset, nmi_n => '1', irq_n => '1', di => D_IN, do => D, addr => A, we => we, debugPc => debugPc, debugOpcode => debugOpcode, debugA => debugA, debugX => debugX, debugY => debugY, debugS => debugS ); end generate; T65_core: if use_T65_core generate cpu : entity work.T65 port map ( Mode => "00", Abort_n => '1', SO_n => '1', Res_n => not reset, Enable => not PRE_PHASE_ZERO_sig, Clk => Q3, Rdy => '1', IRQ_n => '1', NMI_n => '1', R_W_n => R_W_n, Sync => open, EF => open, MF => open, XF => open, ML_n => open, VP_n => open, VDA => open, VPA => open, unsigned(A(23 downto 0)) => A_BIG, DI(7 downto 0) => std_logic_vector(D_IN), unsigned(DO(7 downto 0)) => D, DEBUG => DEBUG ); A <= A_BIG( 15 downto 0); we <= not R_W_n; debugOpcode <= unsigned(DEBUG.I); -- instruction debugA <= unsigned(DEBUG.A); -- A reg debugX <= unsigned(DEBUG.X); -- X reg debugY <= unsigned(DEBUG.Y); -- Y reg debugS <= unsigned(DEBUG.S); -- stack pointer --<= DEBUG.P; -- processor flags end generate; -- Original Apple had asynchronous ROMs. We use a synchronous ROM -- that needs its address earlier, hence the odd clock. auto_rom: if use_auto_rom generate -- apple II roms roms : entity work.apple_II_auto_rom port map ( addr => std_logic_vector(rom_addr), clk => CLK_14M, unsigned(DATA) => rom_out); end generate; bios_rom: if use_bios_rom generate -- test bios roms : entity work.bios_rom port map ( addr => std_logic_vector(rom_addr), clk => CLK_14M, unsigned(DATA) => rom_out); end generate; end rtl;