------------------------------------------------------------------------------- -- -- 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; entity apple2 is port ( CLK_14M : in std_logic; -- 14.31818 MHz master clock CLK_2M : out std_logic; CPU_WAIT : in 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(17 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); pcDebugOut : out unsigned(15 downto 0); opcodeDebugOut : out unsigned(7 downto 0); laudio : out std_logic_vector(7 downto 0); raudio : out std_logic_vector(7 downto 0); mb_enabled : in std_logic; speaker : out std_logic -- One-bit speaker output ); end apple2; architecture rtl of apple2 is component ramcard is port ( mclk28: in std_logic; reset_in: in std_logic; addr: in std_logic_vector(15 downto 0); ram_addr: out std_logic_vector(17 downto 0); we: in std_logic; card_ram_we: out std_logic; card_ram_rd: out std_logic; bank1: out std_logic ); end component; -- 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 D_OUT: unsigned(7 downto 0); signal A : unsigned(15 downto 0); signal we : 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 -- ramcard signal card_addr : unsigned(17 downto 0); signal card_ram_rd : std_logic; signal card_ram_we : std_logic; signal ram_card_read : std_logic; signal ram_card_write : std_logic; signal psg_irq_n : std_logic; signal psg_do : unsigned(7 downto 0); signal ioselect : std_logic_vector(7 downto 0); signal devselect : std_logic_vector(7 downto 0); signal R_W_n : std_logic; begin CLK_2M <= Q3; PRE_PHASE_ZERO <= PRE_PHASE_ZERO_sig; ram_addr <= card_addr when PHASE_ZERO = '1' else "00" & VIDEO_ADDRESS; ram_we <= ((we and RAM_SELECT) or (we and ram_card_write)) 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; D <= D_OUT; IO_SELECT <= ioselect; DEVICE_SELECT <= devselect; -- 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'; ioselect <= (others => '0'); devselect <= (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" => devselect(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" => ioselect(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' or ram_card_read = '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 psg_do when (devselect(4) = '1' or ioselect(4) = '1') and mb_enabled = '1' else PD; -- Peripherals LD194 <= LD194_I; timing : entity work.timing_generator port map ( CLK_14M => CLK_14M, CLK_7M => CLK_7M, CAS_N => CAS_N, RAS_N => RAS_N, Q3 => Q3, AX => AX, PHI0 => PHASE_ZERO, PRE_PHI0 => PRE_PHASE_ZERO_sig, COLOR_REF => 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 => VBL, HBL => 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); cpu : entity work.cpu65xx generic map ( pipelineOpcode => false, pipelineAluMux => false, pipelineAluOut => false) port map ( clk => Q3, enable => (not PRE_PHASE_ZERO_sig) and (not CPU_WAIT), reset => reset, nmi_n => '1', irq_n => psg_irq_n, di => D_IN, do => D_OUT, addr => A, we => we, debugPc => pcDebugOut, debugOpcode => opcodeDebugOut ); -- Original Apple had asynchronous ROMs. We use a synchronous ROM -- that needs its address earlier, hence the odd clock. roms : entity work.roms port map ( address => std_logic_vector(rom_addr), clock => CLK_14M, unsigned(q) => rom_out); -- ramcard ram_card_D: component ramcard port map ( mclk28 => CLK_14M, reset_in => reset, addr => std_logic_vector(A), unsigned(ram_addr) => card_addr, we => we, card_ram_we => card_ram_we, card_ram_rd => card_ram_rd, bank1 => open ); ram_card_read <= ROM_SELECT and card_ram_rd; ram_card_write <= ROM_SELECT and card_ram_we; mb : work.mockingboard port map ( CLK_VIA => not Q3, CLK_PSG => not PHASE_ZERO, I_P2_H => not PHASE_ZERO, I_RESET_L => not reset, I_ENA_H => mb_enabled, I_ADDR => std_logic_vector(A)(7 downto 0), I_DATA => std_logic_vector(D_OUT), unsigned(O_DATA) => psg_do, I_RW_L => not we, I_IOSEL_L => not ioselect(4), O_IRQ_L => psg_irq_n, O_AUDIO_L => laudio, O_AUDIO_R => raudio ); end rtl;