From 6ee4eefcb86f2583ad1ac600c0b8719af9d80b63 Mon Sep 17 00:00:00 2001 From: Stefan Date: Tue, 5 Jan 2016 14:07:05 +0100 Subject: [PATCH] add more vhdl --- .gitignore | 63 +++++ Apple2.xise | 455 +++++++++++++++++++++++++++++++++ src/PS2/Keyboard.vhd | 62 +++++ src/apple2.vhd | 310 ++++++++++++++++++++++ src/apple2_top_papilio_duo.vhd | 408 +++++++++++++++++++++++++++++ src/cpu_hexy.vhd | 220 ++++++++++++++++ src/dcm.vhd | 173 +++++++++++++ src/disk_disp.vhd | 189 ++++++++++++++ src/video_generator.vhd | 221 ++++++++++++++++ 9 files changed, 2101 insertions(+) create mode 100644 .gitignore create mode 100644 Apple2.xise create mode 100644 src/PS2/Keyboard.vhd create mode 100644 src/apple2.vhd create mode 100644 src/apple2_top_papilio_duo.vhd create mode 100644 src/cpu_hexy.vhd create mode 100644 src/dcm.vhd create mode 100644 src/disk_disp.vhd create mode 100644 src/video_generator.vhd diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d3ce30 --- /dev/null +++ b/.gitignore @@ -0,0 +1,63 @@ +*~ + +# intermediate build files +*.bgn +*.bit +*.bld +*.cmd_log +*.drc +*.ll +*.lso +*.msd +*.msk +*.ncd +*.ngc +*.ngd +*.ngr +*.pad +*.par +*.pcf +*.prj +*.ptwx +*.rbb +*.rbd +*.stx +*.syr +*.twr +*.twx +*.unroutes +*.ut +*.xpi +*.xst +*_bitgen.xwbt +*_envsettings.html +*_map.map +*_map.mrp +*_map.ngm +*_map.xrpt +*_ngdbuild.xrpt +*_pad.csv +*_pad.txt +*_par.xrpt +*_summary.html +*_summary.xml +*_usage.xml +*_xst.xrpt + +# project-wide generated files +*.gise +par_usage_statistics.html +usage_statistics_webtalk.html +webtalk.log +webtalk_pn.xml + +# generated folders +iseconfig/ +ipcore_dir/ +xlnx_auto_0_xdb/ +xst/ +_ngo/ +_xmsgs/ + +# cmake +build/ diff --git a/Apple2.xise b/Apple2.xise new file mode 100644 index 0000000..eb50a0a --- /dev/null +++ b/Apple2.xise @@ -0,0 +1,455 @@ + + + +
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/PS2/Keyboard.vhd b/src/PS2/Keyboard.vhd new file mode 100644 index 0000000..57040aa --- /dev/null +++ b/src/PS2/Keyboard.vhd @@ -0,0 +1,62 @@ +-- (C) Rui T. Sousa from http://sweet.ua.pt/~a16360 + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +entity Keyboard is + port ( + Reset : in std_logic; + Clock : in std_logic; + PS2Clock : inout std_logic; + PS2Data : inout std_logic; + CodeReady : out std_logic; + ScanCode : out std_logic_vector(9 downto 0) + ); +end Keyboard; + +architecture Behavioral of Keyboard is + + signal Send : std_logic; + signal Command : std_logic_vector(7 downto 0); + signal PS2Busy : std_logic; + signal PS2Error : std_logic; + signal DataReady : std_logic; + signal DataByte : std_logic_vector(7 downto 0); + +begin + + PS2_Controller: entity work.PS2Controller + + generic map( + clk_freq => 14 + ) + port map ( + Reset => Reset, + Clock => Clock, + PS2Clock => PS2Clock, + PS2Data => PS2Data, + Send => Send, + Command => Command, + PS2Busy => PS2Busy, + PS2Error => PS2Error, + DataReady => DataReady, + DataByte => DataByte + ); + + Keyboard_Mapper: entity work.KeyboardMapper + port map ( + Clock => Clock, + Reset => Reset, + PS2Busy => PS2Busy, + PS2Error => PS2Error, + DataReady => DataReady, + DataByte => DataByte, + Send => Send, + Command => Command, + CodeReady => CodeReady, + ScanCode => ScanCode + ); + +end Behavioral; diff --git a/src/apple2.vhd b/src/apple2.vhd new file mode 100644 index 0000000..fb564b9 --- /dev/null +++ b/src/apple2.vhd @@ -0,0 +1,310 @@ +------------------------------------------------------------------------------- +-- +-- 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 +generic ( + + use_monitor_rom : boolean := true; + use_auto_rom : boolean := false + ); + 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 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 + +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); + + 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 + ); + + -- Original Apple had asynchronous ROMs. We use a synchronous ROM + -- that needs its address earlier, hence the odd clock. + + monitor_rom: if use_monitor_rom generate + roms : entity work.main_roms port map ( + addr => rom_addr, + clk => CLK_14M, + dout => rom_out); + end generate; + +auto_rom: if use_auto_rom generate + + roms : entity work.apple_II_auto_rom port map ( + addr => std_logic_vector(rom_addr), + clk => CLK_14M, + unsigned(DATA) => rom_out); +end generate; + +end rtl; diff --git a/src/apple2_top_papilio_duo.vhd b/src/apple2_top_papilio_duo.vhd new file mode 100644 index 0000000..e577f8c --- /dev/null +++ b/src/apple2_top_papilio_duo.vhd @@ -0,0 +1,408 @@ +------------------------------------------------------------------------------- +-- +-- DE2 top-level module for the Apple ][ +-- +-- Stephen A. Edwards, Columbia University, sedwards@cs.columbia.edu +-- +-- From an original by Terasic Technology, Inc. +-- (DE2_TOP.v, part of the DE2 system board CD supplied by Altera) +-- +------------------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity apple2_papilio is + + port ( + -- Clocks + CLK : in std_logic; -- 32 MHz + + RESET_I : in std_logic; -- reset positiv + + + -- SRAM + SRAM_DQ : inout unsigned(7 downto 0); -- Data bus 8 Bits + SRAM_ADDR : out unsigned(20 downto 0); -- Address bus 21 Bits + SRAM_WE_N, -- Write Enable + SRAM_CE_N, -- Chip Enable + SRAM_OE_N : out std_logic; -- Output Enable + + -- SD card interface + + SD_DAT : in std_logic; -- SD Card Data SD pin 7 "DAT 0/DataOut" + SD_DAT3 : out std_logic; -- SD Card Data 3 SD pin 1 "DAT 3/nCS" + SD_CMD : out std_logic; -- SD Card Command SD pin 2 "CMD/DataIn" + SD_CLK : out std_logic; -- SD Card Clock SD pin 5 "CLK" + + -- Led + LED : out std_logic_vector(3 downto 0); + + -- PS/2 port + PS2_DAT, -- Data + PS2_CLK : inout std_logic; -- Clock + + O_AUDIO_L : out std_logic; -- Audio out + O_AUDIO_R : out std_logic; -- Ausdio out + + -- VGA output + VGA_HS, -- H_SYNC + VGA_VS : out std_logic; -- V_SYNC + + VGA_R, -- Red[3:0] + VGA_G, -- Green[3:0] + VGA_B : out unsigned(3 downto 0) -- Blue[3:0] + + ); + +end apple2_papilio; + +architecture datapath of apple2_papilio is + + signal cpuDebugDim : std_logic; -- CPU Debug + signal cpuDebug : std_logic; -- CPU Debug + + signal diskDebugDim : std_logic; -- disk Debug + signal diskDebug : std_logic; -- disk Debug + + signal debug_info_on : std_logic; -- switch debug info screen on / off + + signal VGAR, -- Red[9:0] + VGAG, -- Green[9:0] + VGAB : unsigned(9 downto 0); -- Blue[9:0] + + signal VGAHS, -- H_SYNC + VGAVS : std_logic; -- V_SYNC + + + signal audio : std_logic; -- audio + + -- LED displays + signal LEDG : std_logic_vector(8 downto 0); -- Green LEDs + + -- Buttons and switches + signal KEY : std_logic_vector(3 downto 0); -- Push buttons + + signal CLK_28M, CLK_14M, CLK_2M, PRE_PHASE_ZERO : std_logic; + signal IO_SELECT, DEVICE_SELECT : std_logic_vector(7 downto 0); + signal ADDR : unsigned(15 downto 0); + signal D, PD : unsigned(7 downto 0); + + signal ram_we : std_logic; + signal VIDEO, HBL, VBL, LD194 : std_logic; + signal COLOR_LINE : std_logic; + signal COLOR_LINE_CONTROL : std_logic; + signal GAMEPORT : std_logic_vector(7 downto 0); + signal cpu_pc : unsigned(15 downto 0); + signal cpuDebugOpcode : unsigned(7 downto 0); + signal cpuDebugPc : unsigned(15 downto 0); + signal cpuDebugA : unsigned(7 downto 0); + signal cpuDebugX : unsigned(7 downto 0); + signal cpuDebugY : unsigned(7 downto 0); + signal cpuDebugS : unsigned(7 downto 0); + + signal K : unsigned(7 downto 0); + signal read_key : std_logic; + + signal flash_clk : unsigned(22 downto 0) := (others => '0'); + signal power_on_reset : std_logic := '1'; + signal reset : std_logic; + signal reset_n : std_logic; + + signal speaker : std_logic; + + signal track : unsigned(5 downto 0); + signal image : unsigned(9 downto 0); + signal trackmsb : unsigned(3 downto 0); + signal D1_ACTIVE, D2_ACTIVE : std_logic; + signal track_addr : unsigned(13 downto 0); + signal TRACK_RAM_ADDR : unsigned(13 downto 0); + signal tra : unsigned(15 downto 0); + signal TRACK_RAM_DI : unsigned(7 downto 0); + signal TRACK_RAM_WE : std_logic; + + signal CS_N, MOSI, MISO, SCLK : std_logic; + + signal de_RESET_I : std_logic; + signal color_bw : std_logic; + +begin + + --reset <= (not KEY(3)) or power_on_reset; + reset <= power_on_reset or de_RESET_I; + reset_n <= not power_on_reset; + + + + power_on : process(CLK_14M) + begin + if rising_edge(CLK_14M) then + if flash_clk(22) = '1' then + power_on_reset <= '0'; + end if; + end if; + end process; + + -- In the Apple ][, this was a 555 timer + flash_clkgen : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + flash_clk <= flash_clk + 1; + + end if; + end process; + + -- Use a PLL to divide the 50 MHz down to 28 MHz and 14 MHz + pll : entity work.clock port map ( + CLK_IN_32 => CLK, + CLK_28 => CLK_28M, + CLK_14 => CLK_14M, + RESET => '0', + LOCKED =>open + + ); + + inst_debouncer : entity work.grp_debouncer + + generic map ( + + N => 1, + CNT_VAL => 10000 + + ) + port map ( + + clk_i => CLK_28M, + data_i(0) => RESET_I, + data_o(0) => de_RESET_I, + strb_o => open + + ); + + -- Paddle buttons + GAMEPORT <= "0000" & (not KEY(2 downto 0)) & "0"; + + COLOR_LINE_CONTROL <= COLOR_LINE and color_bw; -- Color or B&W mode + + core : entity work.apple2 + + generic map ( + + use_monitor_rom => false, + use_auto_rom => true + ) + + port map ( + CLK_14M => CLK_14M, + CLK_2M => CLK_2M, + PRE_PHASE_ZERO => PRE_PHASE_ZERO, + FLASH_CLK => flash_clk(22), + reset => reset, + ADDR => ADDR, + ram_addr => SRAM_ADDR(15 downto 0), + D => D, + ram_do => SRAM_DQ(7 downto 0), + PD => PD, + ram_we => ram_we, + VIDEO => VIDEO, + COLOR_LINE => COLOR_LINE, + HBL => HBL, + VBL => VBL, + LD194 => LD194, + K => K, + read_key => read_key, + AN => LEDG(7 downto 4), + GAMEPORT => GAMEPORT, + IO_SELECT => IO_SELECT, + DEVICE_SELECT => DEVICE_SELECT, + debugPc => cpuDebugPc, + debugOpcode => cpuDebugOpcode, + debugA => cpuDebugA, + debugX => cpuDebugX, + debugY => cpuDebugY, + debugS => cpuDebugS, + speaker => speaker + ); + + vga : entity work.vga_controller port map ( + CLK_28M => CLK_28M, + VIDEO => VIDEO, + COLOR_LINE => COLOR_LINE_CONTROL, + HBL => HBL, + VBL => VBL, + LD194 => LD194, + --VGA_CLK => open, + VGA_HS => VGAHS, + VGA_VS => VGAVS, + --VGA_BLANK => open, + VGA_R => VGAR, + VGA_G => VGAG, + VGA_B => VGAB + ); + + hexyInstance : entity work.cpu_hexy + generic map ( + xoffset => 200, + yoffset => 60 + ) + port map ( + clk => CLK_28M, + vSync => VGAVS, + hSync => VGAHS, + video => cpuDebug, + dim => cpuDebugDim, -- 1 if aktiv + + spyAddr => ADDR, + spyPc => cpuDebugPc, + spyDo => D, + + spyOpcode => cpuDebugOpcode, + spyA => cpuDebugA, + spyX => cpuDebugX, + spyY => cpuDebugY, + spyS => cpuDebugS + ); + + disk_hexyInstance : entity work.disk_disp + generic map ( + xoffset => 200, + yoffset => 70 + ) + port map ( + clk => CLK_28M, + vSync => VGAVS, + hSync => VGAHS, + video => diskDebug, + dim => diskDebugDim, -- 1 if aktiv + + track => track, + image => image, + trackmsb => trackmsb + + + ); + + + process(CLK_28M) + begin + if rising_edge(CLK_28M) then + VGA_R <= VGAR( 9 downto 6); + VGA_G <= VGAG( 9 downto 6); + VGA_B <= VGAB( 9 downto 6); + + if debug_info_on = '1' then + + if cpuDebugDim = '1' then + VGA_R <= cpuDebug & vgaR(8 downto 6); + VGA_G <= cpuDebug & vgaG(8 downto 6); + VGA_B <= cpuDebug & vgaB(8 downto 6); + end if; + + if diskDebugDim = '1' then + VGA_R <= diskDebug & vgaR(8 downto 6); + VGA_G <= diskDebug & vgaG(8 downto 6); + VGA_B <= diskDebug & vgaB(8 downto 6); + end if; + end if; + + end if; + end process; + + + + VGA_VS <= VGAVS; + VGA_HS <= VGAHS; + + keyboard : entity work.keyboard_apple + port map ( + PS2_Clk => PS2_CLK, + PS2_Data => PS2_DAT, + CLK_14M => CLK_14M, + reset => reset, + read => read_key, + image_out => image, + debug_info_on => debug_info_on, + K => K, + out_color_bw => color_bw + ); + + disk : entity work.disk_ii port map ( + CLK_14M => CLK_14M, + CLK_2M => CLK_2M, + PRE_PHASE_ZERO => PRE_PHASE_ZERO, + IO_SELECT => IO_SELECT(6), + DEVICE_SELECT => DEVICE_SELECT(6), + RESET => reset, + A => ADDR, + D_IN => D, + D_OUT => PD, + TRACK => TRACK, + TRACK_ADDR => TRACK_ADDR, + D1_ACTIVE => D1_ACTIVE, + D2_ACTIVE => D2_ACTIVE, + ram_write_addr => TRACK_RAM_ADDR, + ram_di => TRACK_RAM_DI, + ram_we => TRACK_RAM_WE + ); + + sdcard_interface : entity work.spi_controller port map ( + CLK_14M => CLK_14M, + RESET => RESET, + + CS_N => CS_N, + MOSI => MOSI, + MISO => MISO, + SCLK => SCLK, + + track => TRACK, + image => image, + + ram_write_addr => TRACK_RAM_ADDR, + ram_di => TRACK_RAM_DI, + ram_we => TRACK_RAM_WE + ); + + + inst_dac : entity work.dac port map ( + + clk_i => CLK_28M, + res_n_i => reset_n, + dac_i => "00" & speaker & "00000", + dac_o => audio + ); + + + + O_AUDIO_L <= audio; + O_AUDIO_R <= audio; + --image <= SW(9 downto 0); + + SD_DAT3 <= CS_N; + SD_CMD <= MOSI; + MISO <= SD_DAT; + SD_CLK <= SCLK; + + + + + -- Current disk track on middle two digits + trackmsb <= "00" & track(5 downto 4); + + SRAM_DQ(7 downto 0) <= D when ram_we = '1' else (others => 'Z'); + SRAM_ADDR(20 downto 16 ) <= (others => '0'); + + SRAM_CE_N <= '0'; + SRAM_WE_N <= not ram_we; + SRAM_OE_N <= ram_we; + + LED(1) <= D1_ACTIVE; -- Disk 1 + LED(2) <= D2_ACTIVE; -- Disk 2 + + LEDG(3 downto 1) <= (others => '0'); + + LED(0) <= '0'; + LED(3) <= '0'; + + + +end datapath; diff --git a/src/cpu_hexy.vhd b/src/cpu_hexy.vhd new file mode 100644 index 0000000..57e987c --- /dev/null +++ b/src/cpu_hexy.vhd @@ -0,0 +1,220 @@ + +library IEEE; +use ieee.std_logic_1164.ALL; +use ieee.numeric_std.ALL; + +-- Print CPU register on the VGA screen + +entity cpu_hexy is + generic ( + yOffset : integer := 100; + xOffset : integer := 100 + ); + port ( + clk : in std_logic; + vSync : in std_logic; + hSync : in std_logic; + video : out std_logic; + dim : out std_logic; -- '1' if aktive + + spyAddr : in unsigned(15 downto 0); + spyPc : in unsigned(15 downto 0); + spyDo : in unsigned(7 downto 0); + spyOpcode : in unsigned(7 downto 0); + spyA : in unsigned(7 downto 0); + spyX : in unsigned(7 downto 0); + spyY : in unsigned(7 downto 0); + spyS : in unsigned(7 downto 0) + ); +end entity; + +architecture rtl of cpu_hexy is + signal oldV : std_logic; + signal oldH : std_logic; + + signal vPos : integer range 0 to 1023 := 0; + signal hPos : integer range 0 to 2047 := 0; + + signal localX : unsigned(8 downto 0) := (others =>'0'); + signal localX2 : unsigned(8 downto 0) := (others =>'0'); + signal localX3 : unsigned(8 downto 0) := (others =>'0'); + signal localY : unsigned(3 downto 0) := (others =>'0'); + signal runY : std_logic := '0'; + signal runX : std_logic := '0'; + + signal cChar : unsigned(5 downto 0) := (others =>'0'); + signal pixels : unsigned(0 to 63) := (others =>'0'); + +begin + process(clk) + begin + if rising_edge(clk) then + if hSync = '0' and oldH = '1' then + hPos <= 0; + vPos <= vPos + 1; + else + hPos <= hPos + 1; + end if; + if vSync = '0' and oldV = '1' then + vPos <= 0; + end if; + oldH <= hSync; + oldV <= vSync; + end if; + end process; + + process(clk) + begin + if rising_edge(clk) then + if hPos = xOffset then + localX <= (others => '0'); + runX <= '1'; + if vPos = yOffset then + localY <= (others => '0'); + runY <= '1'; + end if; + elsif runX = '1' + and localX = "111111111" then + runX <= '0'; + if localY = "111" then + runY <= '0'; + else + localY <= localY + 1; + end if; + else + localX <= localX + 1; + end if; + end if; + end process; + + process(clk) + begin + if rising_edge(clk) then + case localX(8 downto 3) is + when "000000" => cChar <= "001010"; -- A + when "000001" => cChar <= "001101"; -- D + when "000010" => cChar <= "001101"; -- D + when "000011" => cChar <= "011011"; -- R + when "000100" => cChar <= "111110"; -- : + when "000101" => cChar <= "00" & spyAddr(15 downto 12); + when "000110" => cChar <= "00" & spyAddr(11 downto 8); + when "000111" => cChar <= "00" & spyAddr( 7 downto 4); + when "001000" => cChar <= "00" & spyAddr( 3 downto 0); + when "001001" => cChar <= "111111"; -- + when "001010" => cChar <= "111111"; -- + when "001011" => cChar <= "011001"; -- P + when "001100" => cChar <= "001100"; -- C + when "001101" => cChar <= "111110"; -- : + when "001110" => cChar <= "00" & spyPc(15 downto 12); + when "001111" => cChar <= "00" & spyPc(11 downto 8); + when "010000" => cChar <= "00" & spyPc( 7 downto 4); + when "010001" => cChar <= "00" & spyPc( 3 downto 0); + when "010010" => cChar <= "111111"; -- + when "010011" => cChar <= "111111"; -- + when "010100" => cChar <= "001101"; -- D + when "010101" => cChar <= "011000"; -- O + when "010110" => cChar <= "111110"; -- : + when "010111" => cChar <= "00" & spyDo(7 downto 4); + when "011000" => cChar <= "00" & spyDo(3 downto 0); + when "011001" => cChar <= "111111"; -- + when "011010" => cChar <= "111111"; -- + when "011011" => cChar <= "011000"; -- O + when "011100" => cChar <= "011001"; -- P + when "011101" => cChar <= "001100"; -- C + when "011110" => cChar <= "111110"; -- : + when "011111" => cChar <= "00" & spyOpcode(7 downto 4); + when "100000" => cChar <= "00" & spyOpcode(3 downto 0); + when "100001" => cChar <= "111111"; -- + when "100010" => cChar <= "111111"; -- + when "100011" => cChar <= "001010"; -- A + when "100100" => cChar <= "111110"; -- : + when "100101" => cChar <= "00" & spyA(7 downto 4); + when "100110" => cChar <= "00" & spyA(3 downto 0); + when "100111" => cChar <= "111111"; -- + when "101000" => cChar <= "111111"; -- + when "101001" => cChar <= "100001"; -- X + when "101010" => cChar <= "111110"; -- : + when "101011" => cChar <= "00" & spyX(7 downto 4); + when "101100" => cChar <= "00" & spyX(3 downto 0); + when "101101" => cChar <= "111111"; -- + when "101110" => cChar <= "111111"; -- + when "101111" => cChar <= "100010"; -- Y + when "110000" => cChar <= "111110"; -- : + when "110001" => cChar <= "00" & spyY(7 downto 4); + when "110010" => cChar <= "00" & spyY(3 downto 0); + when "110011" => cChar <= "111111"; -- + when "110100" => cChar <= "111111"; -- + when "110101" => cChar <= "011100"; -- S + when "110110" => cChar <= "111110"; -- : + when "110111" => cChar <= "00" & spyS(7 downto 4); + when "111000" => cChar <= "00" & spyS(3 downto 0); + when others => cChar <= (others => '1'); + end case; + end if; + end process; + + process(clk) + begin + if rising_edge(clk) then + localX2 <= localX; + localX3 <= localX2; + if (runY = '0') + or (runX = '0') then + pixels <= (others => '0'); + else + case cChar is + when "000000" => pixels <= X"3C666E7666663C00"; -- 0 + when "000001" => pixels <= X"1818381818187E00"; -- 1 + when "000010" => pixels <= X"3C66060C30607E00"; -- 2 + when "000011" => pixels <= X"3C66061C06663C00"; -- 3 + when "000100" => pixels <= X"060E1E667F060600"; -- 4 + when "000101" => pixels <= X"7E607C0606663C00"; -- 5 + when "000110" => pixels <= X"3C66607C66663C00"; -- 6 + when "000111" => pixels <= X"7E660C1818181800"; -- 7 + when "001000" => pixels <= X"3C66663C66663C00"; -- 8 + when "001001" => pixels <= X"3C66663E06663C00"; -- 9 + + when "001010" => pixels <= X"183C667E66666600"; -- A + when "001011" => pixels <= X"7C66667C66667C00"; -- B + when "001100" => pixels <= X"3C66606060663C00"; -- C + when "001101" => pixels <= X"786C6666666C7800"; -- D + when "001110" => pixels <= X"7E60607860607E00"; -- E + when "001111" => pixels <= X"7E60607860606000"; -- F + when "010000" => pixels <= X"3C66606E66663C00"; -- G + when "010001" => pixels <= X"6666667E66666600"; -- H + when "010010" => pixels <= X"3C18181818183C00"; -- I + when "010011" => pixels <= X"1E0C0C0C0C6C3800"; -- J + when "010100" => pixels <= X"666C7870786C6600"; -- K + when "010101" => pixels <= X"6060606060607E00"; -- L + when "010110" => pixels <= X"63777F6B63636300"; -- M + when "010111" => pixels <= X"66767E7E6E666600"; -- N + when "011000" => pixels <= X"3C66666666663C00"; -- O + when "011001" => pixels <= X"7C66667C60606000"; -- P + when "011010" => pixels <= X"3C666666663C0E00"; -- Q + when "011011" => pixels <= X"7C66667C786C6600"; -- R + when "011100" => pixels <= X"3C66603C06663C00"; -- S + when "011101" => pixels <= X"7E18181818181800"; -- T + when "011110" => pixels <= X"6666666666663C00"; -- U + when "011111" => pixels <= X"66666666663C1800"; -- V + when "100000" => pixels <= X"6363636B7F776300"; -- W + when "100001" => pixels <= X"66663C183C666600"; -- X + when "100010" => pixels <= X"6666663C18181800"; -- Y + when "100011" => pixels <= X"7E060C1830607E00"; -- Z + when "111110" => pixels <= X"0000180000180000"; -- : + when others => pixels <= X"0000000000000000"; -- space + end case; + end if; + end if; + end process; + + process(clk) + begin + if rising_edge(clk) then + video <= pixels(to_integer(localY & localX3(2 downto 0))); + end if; + end process; + + dim <= runX and runY; + +end architecture; + diff --git a/src/dcm.vhd b/src/dcm.vhd new file mode 100644 index 0000000..bfaf443 --- /dev/null +++ b/src/dcm.vhd @@ -0,0 +1,173 @@ +-- file: clock.vhd +-- +-- (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved. +-- +-- This file contains confidential and proprietary information +-- of Xilinx, Inc. and is protected under U.S. and +-- international copyright and other intellectual property +-- laws. +-- +-- DISCLAIMER +-- This disclaimer is not a license and does not grant any +-- rights to the materials distributed herewith. Except as +-- otherwise provided in a valid license issued to you by +-- Xilinx, and to the maximum extent permitted by applicable +-- law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND +-- WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES +-- AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING +-- BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- +-- INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and +-- (2) Xilinx shall not be liable (whether in contract or tort, +-- including negligence, or under any other theory of +-- liability) for any loss or damage of any kind or nature +-- related to, arising under or in connection with these +-- materials, including for any direct, or any indirect, +-- special, incidental, or consequential loss or damage +-- (including loss of data, profits, goodwill, or any type of +-- loss or damage suffered as a result of any action brought +-- by a third party) even if such damage or loss was +-- reasonably foreseeable or Xilinx had been advised of the +-- possibility of the same. +-- +-- CRITICAL APPLICATIONS +-- Xilinx products are not designed or intended to be fail- +-- safe, or for use in any application requiring fail-safe +-- performance, such as life-support or safety devices or +-- systems, Class III medical devices, nuclear facilities, +-- applications related to the deployment of airbags, or any +-- other applications that could lead to death, personal +-- injury, or severe property or environmental damage +-- (individually and collectively, "Critical +-- Applications"). Customer assumes the sole risk and +-- liability of any use of Xilinx products in Critical +-- Applications, subject only to applicable laws and +-- regulations governing limitations on product liability. +-- +-- THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS +-- PART OF THIS FILE AT ALL TIMES. +-- +------------------------------------------------------------------------------ +-- User entered comments +------------------------------------------------------------------------------ +-- None +-- +------------------------------------------------------------------------------ +-- "Output Output Phase Duty Pk-to-Pk Phase" +-- "Clock Freq (MHz) (degrees) Cycle (%) Jitter (ps) Error (ps)" +------------------------------------------------------------------------------ +-- CLK_OUT1____28.000______0.000______50.0______380.844____257.392 +-- CLK_OUT2____14.000______0.000______50.0______441.389____257.392 +-- +------------------------------------------------------------------------------ +-- "Input Clock Freq (MHz) Input Jitter (UI)" +------------------------------------------------------------------------------ +-- __primary__________32.000____________0.010 + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.all; +use ieee.numeric_std.all; + +library unisim; +use unisim.vcomponents.all; + +entity clock is +port + (-- Clock in ports + CLK_IN_32 : in std_logic; + -- Clock out ports + CLK_28 : out std_logic; + CLK_14 : out std_logic; + -- Status and control signals + RESET : in std_logic; + LOCKED : out std_logic + ); +end clock; + +architecture xilinx of clock is + attribute CORE_GENERATION_INFO : string; + attribute CORE_GENERATION_INFO of xilinx : architecture is "clock,clk_wiz_v3_6,{component_name=clock,use_phase_alignment=true,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,feedback_source=FDBK_AUTO,primtype_sel=PLL_BASE,num_out_clk=2,clkin1_period=31.250,clkin2_period=31.250,use_power_down=false,use_reset=true,use_locked=true,use_inclk_stopped=false,use_status=false,use_freeze=false,use_clk_valid=false,feedback_type=SINGLE,clock_mgr_type=AUTO,manual_override=false}"; + -- Input clock buffering / unused connectors + signal clkin1 : std_logic; + -- Output clock buffering / unused connectors + signal clkfbout : std_logic; + signal clkfbout_buf : std_logic; + signal clkout0 : std_logic; + signal clkout1 : std_logic; + signal clkout2_unused : std_logic; + signal clkout3_unused : std_logic; + signal clkout4_unused : std_logic; + signal clkout5_unused : std_logic; + -- Unused status signals + +begin + + + -- Input buffering + -------------------------------------- + clkin1_buf : IBUFG + port map + (O => clkin1, + I => CLK_IN_32); + + + -- Clocking primitive + -------------------------------------- + -- Instantiation of the PLL primitive + -- * Unused inputs are tied off + -- * Unused outputs are labeled unused + + pll_base_inst : PLL_BASE + generic map + (BANDWIDTH => "OPTIMIZED", + CLK_FEEDBACK => "CLKFBOUT", + COMPENSATION => "SYSTEM_SYNCHRONOUS", + DIVCLK_DIVIDE => 1, + CLKFBOUT_MULT => 14, + CLKFBOUT_PHASE => 0.000, + CLKOUT0_DIVIDE => 16, + CLKOUT0_PHASE => 0.000, + CLKOUT0_DUTY_CYCLE => 0.500, + CLKOUT1_DIVIDE => 32, + CLKOUT1_PHASE => 0.000, + CLKOUT1_DUTY_CYCLE => 0.500, + CLKIN_PERIOD => 31.250, + REF_JITTER => 0.010) + port map + -- Output clocks + (CLKFBOUT => clkfbout, + CLKOUT0 => clkout0, + CLKOUT1 => clkout1, + CLKOUT2 => clkout2_unused, + CLKOUT3 => clkout3_unused, + CLKOUT4 => clkout4_unused, + CLKOUT5 => clkout5_unused, + -- Status and control signals + LOCKED => LOCKED, + RST => RESET, + -- Input clock control + CLKFBIN => clkfbout_buf, + CLKIN => clkin1); + + -- Output buffering + ------------------------------------- + clkf_buf : BUFG + port map + (O => clkfbout_buf, + I => clkfbout); + + + clkout1_buf : BUFG + port map + (O => CLK_28, + I => clkout0); + + + + clkout2_buf : BUFG + port map + (O => CLK_14, + I => clkout1); + +end xilinx; diff --git a/src/disk_disp.vhd b/src/disk_disp.vhd new file mode 100644 index 0000000..7de8aae --- /dev/null +++ b/src/disk_disp.vhd @@ -0,0 +1,189 @@ + +library IEEE; +use ieee.std_logic_1164.ALL; +use ieee.numeric_std.ALL; + +-- Prints track and disk image + +entity disk_disp is + generic ( + yOffset : integer := 100; + xOffset : integer := 100 + ); + port ( + clk : in std_logic; + vSync : in std_logic; + hSync : in std_logic; + video : out std_logic; + dim : out std_logic; + + track : in unsigned(5 downto 0); + image : in unsigned(9 downto 0); + trackmsb : in unsigned(3 downto 0) + + ); +end entity; + +architecture rtl of disk_disp is + signal oldV : std_logic; + signal oldH : std_logic; + + signal vPos : integer range 0 to 1023; + signal hPos : integer range 0 to 2047; + + signal localX : unsigned(8 downto 0); + signal localX2 : unsigned(8 downto 0); + signal localX3 : unsigned(8 downto 0); + signal localY : unsigned(3 downto 0); + signal runY : std_logic; + signal runX : std_logic; + + signal cChar : unsigned(5 downto 0); + signal pixels : unsigned(0 to 63); + +begin + process(clk) + begin + if rising_edge(clk) then + if hSync = '0' and oldH = '1' then + hPos <= 0; + vPos <= vPos + 1; + else + hPos <= hPos + 1; + end if; + if vSync = '0' and oldV = '1' then + vPos <= 0; + end if; + oldH <= hSync; + oldV <= vSync; + end if; + end process; + + process(clk) + begin + if rising_edge(clk) then + if hPos = xOffset then + localX <= (others => '0'); + runX <= '1'; + if vPos = yOffset then + localY <= (others => '0'); + runY <= '1'; + end if; + elsif runX = '1' + and localX = "111111111" then + runX <= '0'; + if localY = "111" then + runY <= '0'; + else + localY <= localY + 1; + end if; + else + localX <= localX + 1; + end if; + end if; + end process; + + process(clk) + begin + if rising_edge(clk) then + case localX(8 downto 3) is + when "000000" => cChar <= "011101"; -- T + when "000001" => cChar <= "011011"; -- R + when "000010" => cChar <= "001010"; -- A + when "000011" => cChar <= "001100"; -- C + when "000100" => cChar <= "010100"; -- K + when "000101" => cChar <= "111110"; -- : + when "000110" => cChar <= "0000" & track( 5 downto 4); + when "000111" => cChar <= "00" & track( 3 downto 0); + + when "001000" => cChar <= "111111"; -- ; + when "001001" => cChar <= "111111"; -- + when "001010" => cChar <= "111111"; -- + when "001011" => cChar <= "010010"; -- I + when "001100" => cChar <= "010110"; -- M + when "001101" => cChar <= "111110"; -- A + when "001110" => cChar <= "111111"; -- G + when "001111" => cChar <= "111111"; -- E + when "010000" => cChar <= "111111"; --: + when "010001" => cChar <= "0000" & image( 5 downto 4); + when "010010" => cChar <= "00" & image( 3 downto 0); + when "010011" => cChar <= "111111"; -- + when "010100" => cChar <= "001101"; -- D + when "010101" => cChar <= "011000"; -- O + when "010110" => cChar <= "111110"; -- : + when "010111" => cChar <= "111111"; + when "011000" => cChar <= "00" & trackmsb( 3 downto 0); + when "011001" => cChar <= "111111"; -- + + + + when others => cChar <= (others => '1'); + end case; + end if; + end process; + + process(clk) + begin + if rising_edge(clk) then + localX2 <= localX; + localX3 <= localX2; + if (runY = '0') + or (runX = '0') then + pixels <= (others => '0'); + else + case cChar is + when "000000" => pixels <= X"3C666E7666663C00"; -- 0 + when "000001" => pixels <= X"1818381818187E00"; -- 1 + when "000010" => pixels <= X"3C66060C30607E00"; -- 2 + when "000011" => pixels <= X"3C66061C06663C00"; -- 3 + when "000100" => pixels <= X"060E1E667F060600"; -- 4 + when "000101" => pixels <= X"7E607C0606663C00"; -- 5 + when "000110" => pixels <= X"3C66607C66663C00"; -- 6 + when "000111" => pixels <= X"7E660C1818181800"; -- 7 + when "001000" => pixels <= X"3C66663C66663C00"; -- 8 + when "001001" => pixels <= X"3C66663E06663C00"; -- 9 + + when "001010" => pixels <= X"183C667E66666600"; -- A + when "001011" => pixels <= X"7C66667C66667C00"; -- B + when "001100" => pixels <= X"3C66606060663C00"; -- C + when "001101" => pixels <= X"786C6666666C7800"; -- D + when "001110" => pixels <= X"7E60607860607E00"; -- E + when "001111" => pixels <= X"7E60607860606000"; -- F + when "010000" => pixels <= X"3C66606E66663C00"; -- G + when "010001" => pixels <= X"6666667E66666600"; -- H + when "010010" => pixels <= X"3C18181818183C00"; -- I + when "010011" => pixels <= X"1E0C0C0C0C6C3800"; -- J + when "010100" => pixels <= X"666C7870786C6600"; -- K + when "010101" => pixels <= X"6060606060607E00"; -- L + when "010110" => pixels <= X"63777F6B63636300"; -- M + when "010111" => pixels <= X"66767E7E6E666600"; -- N + when "011000" => pixels <= X"3C66666666663C00"; -- O + when "011001" => pixels <= X"7C66667C60606000"; -- P + when "011010" => pixels <= X"3C666666663C0E00"; -- Q + when "011011" => pixels <= X"7C66667C786C6600"; -- R + when "011100" => pixels <= X"3C66603C06663C00"; -- S + when "011101" => pixels <= X"7E18181818181800"; -- T + when "011110" => pixels <= X"6666666666663C00"; -- U + when "011111" => pixels <= X"66666666663C1800"; -- V + when "100000" => pixels <= X"6363636B7F776300"; -- W + when "100001" => pixels <= X"66663C183C666600"; -- X + when "100010" => pixels <= X"6666663C18181800"; -- Y + when "100011" => pixels <= X"7E060C1830607E00"; -- Z + when "111110" => pixels <= X"0000180000180000"; -- : + when others => pixels <= X"0000000000000000"; -- space + end case; + end if; + end if; + end process; + + process(clk) + begin + if rising_edge(clk) then + video <= pixels(to_integer(localY & localX3(2 downto 0))); + end if; + end process; + + dim <= runX and runY; + +end architecture; + diff --git a/src/video_generator.vhd b/src/video_generator.vhd new file mode 100644 index 0000000..e24819f --- /dev/null +++ b/src/video_generator.vhd @@ -0,0 +1,221 @@ +------------------------------------------------------------------------------- +-- +-- Apple ][ Video Generation Logic +-- +-- Stephen A. Edwards, sedwards@cs.columbia.edu +-- +-- This takes data from memory and various mode switches to produce the +-- serial one-bit video data stream. +-- +------------------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity video_generator is + + port ( + CLK_14M : in std_logic; -- 14.31818 MHz master clock + CLK_7M : in std_logic; + AX : in std_logic; + CAS_N : in std_logic; + TEXT_MODE : in std_logic; + PAGE2 : in std_logic; + HIRES_MODE : in std_logic; + MIXED_MODE : in std_logic; + H0 : in std_logic; + VA : in std_logic; + VB : in std_logic; + VC : in std_logic; + V2 : in std_logic; + V4 : in std_logic; + BLANK : in std_logic; + DL : in unsigned(7 downto 0); -- Data from RAM + LDPS_N : in std_logic; + LD194 : in std_logic; + FLASH_CLK : in std_logic; -- Low-frequency flashing text clock + HIRES : out std_logic; + VIDEO : out std_logic; + COLOR_LINE : out std_logic + ); + +end video_generator; + +architecture rtl of video_generator is + + signal char_rom_addr : unsigned(8 downto 0); + signal char_rom_out : unsigned(4 downto 0); + signal text_shiftreg : unsigned(5 downto 0); + signal invert_character : std_logic; + signal text_pixel : std_logic; -- B2 p11 + signal blank_delayed : std_logic; + signal video_sig : std_logic; -- output of B10 p5 + signal graph_shiftreg : unsigned(7 downto 0); + signal graphics_time_1, graphics_time_2, + graphics_time_3 : std_logic; -- B5 p2, B8 p15, B8 p2 + signal lores_time : std_logic; -- A11 p6 + signal pixel_select : std_logic_vector(1 downto 0); -- A10 p14, A10 p15 + signal hires_delayed : std_logic; -- A11 p9 + +begin + + ----------------------------------------------------------------------------- + -- + -- Text Mode Circuitry + -- + -- The character ROM drives a parallel-to-serial shift register + -- whose output is selectively inverted by inverted or flashing text + -- + ----------------------------------------------------------------------------- + + char_rom_addr <= DL(5 downto 0) & VC & VB & VA; + + thecharrom : entity work.character_rom + port map( + addr => char_rom_addr, + clk => CLK_14M, -- FIXME: a lower frequency? + dout => char_rom_out + ); + + -- Parallel-to-serial shifter for text mode + -- The Apple actually used LDPS_N as the clock, not 14M; this is equivalent + A3_74166: process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if CLK_7M = '0' then + if LDPS_N = '0' then -- load + text_shiftreg <= char_rom_out & "0"; + else -- shift + text_shiftreg <= '0' & text_shiftreg(5 downto 1); + end if; + end if; + end if; + end process; + + -- Latch and decoder for flashing/inverted text + -- Comprises part of B11, B13, and A10 + flash_invert : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if LD194 = '0' then + invert_character <= not (DL(7) or (DL(6) and FLASH_CLK)); + end if; + end if; + end process; + + text_pixel <= text_shiftreg(0) xor invert_character; + + ----------------------------------------------------------------------------- + -- + -- Lores and Hires Mode Circuitry + -- + -- An eight-bit shift register that either shifts (hires mode) or rotates + -- the two nibbles (lores) followed by a mux that selects the video + -- data from the text mode display, the hires shift register (possibly + -- delayed by a 14M clock pulse), or one of the bits in the lores shift + -- register. + -- + ----------------------------------------------------------------------------- + + -- Original Apple clocked this shift register on the rising edge of RAS_N + B5B8_74LS174 : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if AX = '1' and CAS_N = '0' then + graphics_time_3 <= graphics_time_2; + graphics_time_2 <= graphics_time_1; + graphics_time_1 <= not (TEXT_MODE or (V2 and V4 and MIXED_MODE)); + end if; + end if; + end process; + + COLOR_LINE <= graphics_time_1; + + HIRES <= HIRES_MODE and graphics_time_3; -- to address generator + + lores_time <= not HIRES_MODE and graphics_time_3; + + A8A10_74LS194 : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if LD194 = '0' then + if lores_time = '1' then -- LORES mode + pixel_select <= VC & H0; + else -- HIRES mode + pixel_select <= graphics_time_1 & DL(7); + end if; + end if; + end if; + end process; + + -- Shift hires pixels by one 14M cycle to get orange and blue + A11_74LS74 : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + hires_delayed <= graph_shiftreg(0); + end if; + end process; + + -- A pair of four-bit universal shift registers that either + -- shift the whole byte (hires mode) or rotate the two nibbles (lores mode) + B4B9_74LS194 : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if LD194 = '0' then + graph_shiftreg <= DL; + else + if lores_time = '1' then -- LORES configuration + graph_shiftreg <= graph_shiftreg(4) & graph_shiftreg(7 downto 5) & + graph_shiftreg(0) & graph_shiftreg(3 downto 1); + else -- HIRES configuration + if CLK_7M = '0' then + graph_shiftreg <= graph_shiftreg(4) & graph_shiftreg(7 downto 1); + end if; + end if; + end if; + end if; + end process; + + -- Synchronize BLANK to LD194 + A10_74LS194: process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if LD194 = '0' then + blank_delayed <= BLANK; + end if; + end if; + end process; + + -- Video output mux and flip-flop + A9B10_74LS151 : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if blank_delayed = '0' then + if lores_time = '1' then -- LORES mode + case pixel_select is + when "00" => video_sig <= graph_shiftreg(0); + when "01" => video_sig <= graph_shiftreg(2); + when "10" => video_sig <= graph_shiftreg(4); + when "11" => video_sig <= graph_shiftreg(6); + when others => video_sig <= 'X'; + end case; + else + if pixel_select(1) = '0' then -- TEXT mode + video_sig <= text_pixel; + else -- HIRES mode + if pixel_select(0) = '1' then + video_sig <= hires_delayed; + else + video_sig <= graph_shiftreg(0); + end if; + end if; + end if; + else + video_sig <= '0'; + end if; + end if; + end process; + + VIDEO <= video_sig; + +end rtl;