From 6cdec37da083f26265eae5e15992d019eb9f0e2f Mon Sep 17 00:00:00 2001 From: sorgelig Date: Sun, 29 Dec 2019 09:42:03 +0800 Subject: [PATCH] Use other base - fixes top/bottom text. --- Arcade-Pacman.qsf | 2 +- Arcade-Pacman.sv | 10 +- files.qip | 1 + pacman.vhd | 909 ++++++++++++++++++++++++++----------------- pacman_video.vhd | 419 ++++++++++++-------- pacman_vram_addr.vhd | 273 +++++++++++++ 6 files changed, 1078 insertions(+), 536 deletions(-) create mode 100644 pacman_vram_addr.vhd diff --git a/Arcade-Pacman.qsf b/Arcade-Pacman.qsf index 9ef67a1..f0e66b8 100644 --- a/Arcade-Pacman.qsf +++ b/Arcade-Pacman.qsf @@ -13,7 +13,7 @@ set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top -set_global_assignment -name LAST_QUARTUS_VERSION "17.0.2 Lite Edition" +set_global_assignment -name LAST_QUARTUS_VERSION "17.0.2 Standard Edition" set_global_assignment -name GENERATE_RBF_FILE ON set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files diff --git a/Arcade-Pacman.sv b/Arcade-Pacman.sv index 3c30729..c5d5066 100644 --- a/Arcade-Pacman.sv +++ b/Arcade-Pacman.sv @@ -317,14 +317,10 @@ pacman pacman .O_AUDIO(audio), - //.in0(~{2'b00, m_coin, m_fire, m_down,m_right,m_left,m_up}), - //.in1(~{1'b0, m_start2, m_start1, 5'b00000}), - .in0(~{2'b00,btn_coin_1, m_coin|btn_coin_2, m_cheat , m_down,m_right,m_left,m_up}), - .in1(~{status[12], m_start2|btn_start_2, m_start1|btn_start_1,1'b0,m_down_2,m_right_2,m_left_2,m_up_2}), + .in0_reg(~{2'b00,btn_coin_1, m_coin|btn_coin_2, m_cheat , m_down,m_right,m_left,m_up}), + .in1_reg(~{status[12], m_start2|btn_start_2, m_start1|btn_start_1,1'b0,m_down_2,m_right_2,m_left_2,m_up_2}), - //.dipsw1(8'b1_1_00_11_01), - .dipsw1(m_dip), - .dipsw2(8'b11111111), + .dipsw_reg(m_dip), .RESET(RESET | status[0] | buttons[1]|ioctl_download), .CLK(clk_sys), diff --git a/files.qip b/files.qip index f39bdac..90660f5 100644 --- a/files.qip +++ b/files.qip @@ -5,6 +5,7 @@ set_global_assignment -name VHDL_FILE cpu/T80_MCode.vhd set_global_assignment -name VHDL_FILE cpu/T80_ALU.vhd set_global_assignment -name VHDL_FILE cpu/T80.vhd set_global_assignment -name VHDL_FILE dpram.vhd +set_global_assignment -name VHDL_FILE pacman_vram_addr.vhd set_global_assignment -name VHDL_FILE pacman_video.vhd set_global_assignment -name VHDL_FILE pacman_audio.vhd set_global_assignment -name VHDL_FILE pacman.vhd diff --git a/pacman.vhd b/pacman.vhd index 008ebdb..bf3bfd3 100644 --- a/pacman.vhd +++ b/pacman.vhd @@ -1,7 +1,6 @@ -- -- A simulation model of Pacman hardware -- Copyright (c) MikeJ - January 2006 --- Copyright (c) Sorgelig - 2017 -- -- All rights reserved -- @@ -39,7 +38,6 @@ -- -- Revision list -- --- version 006 Refactoring, 8 sprites support by Sorgelig -- version 005 Papilio release by Jack Gassett -- version 004 spartan3e release -- version 003 Jan 2006 release, general tidy up @@ -51,98 +49,100 @@ library ieee; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; +library UNISIM; + entity PACMAN is - generic( - eight_sprites : boolean := false - ); - port ( - O_VIDEO_R : out std_logic_vector(2 downto 0); - O_VIDEO_G : out std_logic_vector(2 downto 0); - O_VIDEO_B : out std_logic_vector(1 downto 0); - O_HSYNC : out std_logic; - O_VSYNC : out std_logic; - O_HBLANK : out std_logic; - O_VBLANK : out std_logic; - -- - O_AUDIO : out std_logic_vector(7 downto 0); - -- - in0 : in std_logic_vector(7 downto 0); - in1 : in std_logic_vector(7 downto 0); - dipsw1 : in std_logic_vector(7 downto 0); - dipsw2 : in std_logic_vector(7 downto 0); - -- - dn_addr : in std_logic_vector(15 downto 0); - dn_data : in std_logic_vector(7 downto 0); - dn_wr : in std_logic; - -- - RESET : in std_logic; - CLK : in std_logic; - ENA_6 : in std_logic - ); +generic ( + MRTNT : std_logic := '0' -- 1 to descramble Mr TNT ROMs, 0 otherwise +); + port ( + O_VIDEO_R : out std_logic_vector(2 downto 0); + O_VIDEO_G : out std_logic_vector(2 downto 0); + O_VIDEO_B : out std_logic_vector(1 downto 0); + O_HSYNC : out std_logic; + O_VSYNC : out std_logic; + O_HBLANK : out std_logic; + O_VBLANK : out std_logic; + -- + O_AUDIO : out std_logic_vector(7 downto 0); + -- + in0_reg : in std_logic_vector(7 downto 0); + in1_reg : in std_logic_vector(7 downto 0); + dipsw_reg : in std_logic_vector(7 downto 0); + -- + dn_addr : in std_logic_vector(15 downto 0); + dn_data : in std_logic_vector(7 downto 0); + dn_wr : in std_logic; + -- + RESET : in std_logic; + CLK : in std_logic; + ENA_6 : in std_logic + ); end; architecture RTL of PACMAN is - -- timing - signal hcnt : std_logic_vector(8 downto 0) := "010000000"; -- 80 - signal vcnt : std_logic_vector(8 downto 0) := "011111000"; -- 0F8 + -- timing + signal hcnt : std_logic_vector(8 downto 0) := "010000000"; -- 80 + signal vcnt : std_logic_vector(8 downto 0) := "011111000"; -- 0F8 - signal do_hsync : boolean; - signal hsync : std_logic; - signal vsync : std_logic; - signal hblank : std_logic; - signal vblank : std_logic := '1'; + signal do_hsync : boolean; + signal hsync : std_logic; + signal vsync : std_logic; + signal hblank : std_logic; + signal vblank : std_logic := '1'; - -- cpu - signal cpu_m1_l : std_logic; - signal cpu_mreq_l : std_logic; - signal cpu_iorq_l : std_logic; - signal cpu_rd_l : std_logic; - signal cpu_rfsh_l : std_logic; - signal cpu_int_l : std_logic := '1'; - signal cpu_addr : std_logic_vector(15 downto 0); - signal cpu_data_out : std_logic_vector(7 downto 0); - signal cpu_data_in : std_logic_vector(7 downto 0); + -- cpu + signal cpu_ena : std_logic; + signal cpu_m1_l : std_logic; + signal cpu_mreq_l : std_logic; + signal cpu_iorq_l : std_logic; + signal cpu_rd_l : std_logic; + signal cpu_rfsh_l : std_logic; + signal cpu_wait_l : std_logic; + signal cpu_int_l : std_logic; + signal cpu_nmi_l : std_logic; + signal cpu_busrq_l : std_logic; + signal cpu_addr : std_logic_vector(15 downto 0); + signal cpu_data_out : std_logic_vector(7 downto 0); + signal cpu_data_in : std_logic_vector(7 downto 0); - signal program_rom_dinl : std_logic_vector(7 downto 0); - signal program_rom_dinh : std_logic_vector(7 downto 0); - signal sync_bus_cs_l : std_logic; + signal rom_data_out : std_logic_vector(7 downto 0); + signal rom_data : std_logic_vector(7 downto 0); - signal control_reg : std_logic_vector(7 downto 0); - -- - signal sync_bus_db : std_logic_vector(7 downto 0); - signal sync_bus_r_w_l : std_logic; - signal sync_bus_wreq_l : std_logic; - signal sync_bus_stb : std_logic; + signal program_rom_dinl : std_logic_vector(7 downto 0); + signal program_rom_dinh : std_logic_vector(7 downto 0); + signal sync_bus_cs_l : std_logic; - signal cpu_vec_reg : std_logic_vector(7 downto 0); - signal sync_bus_reg : std_logic_vector(7 downto 0); + signal control_reg : std_logic_vector(7 downto 0); + -- + signal vram_addr_ab : std_logic_vector(11 downto 0); + signal ab : std_logic_vector(11 downto 0); - signal hp : std_logic_vector ( 4 downto 0); - signal vp : std_logic_vector ( 4 downto 0); - signal ram_cs : std_logic; - signal ram_data : std_logic_vector(7 downto 0); - signal vram_data : std_logic_vector(7 downto 0); - signal sprite_xy_data : std_logic_vector(7 downto 0); - signal vram_addr : std_logic_vector(11 downto 0); + signal sync_bus_db : std_logic_vector(7 downto 0); + signal sync_bus_r_w_l : std_logic; + signal sync_bus_wreq_l : std_logic; + signal sync_bus_stb : std_logic; - signal iodec_spr_l : std_logic; - signal iodec_out_l : std_logic; - signal iodec_wdr_l : std_logic; - signal iodec_sn1_l : std_logic; - signal iodec_sn2_l : std_logic; - signal iodec_in0_l : std_logic; - signal iodec_in1_l : std_logic; - signal iodec_dipsw1_l : std_logic; - signal iodec_dipsw2_l : std_logic; + signal cpu_vec_reg : std_logic_vector(7 downto 0); + signal sync_bus_reg : std_logic_vector(7 downto 0); - -- watchdog - signal watchdog_cnt : std_logic_vector(3 downto 0); - signal watchdog_reset_l : std_logic; + signal vram_l : std_logic; + signal rams_data_out : std_logic_vector(7 downto 0); + -- more decode + signal wr0_l : std_logic; + signal wr1_l : std_logic; + signal wr2_l : std_logic; + signal iodec_out_l : std_logic; + signal iodec_wdr_l : std_logic; + signal iodec_in0_l : std_logic; + signal iodec_in1_l : std_logic; + signal iodec_dipsw_l : std_logic; - signal sn_we : std_logic; - signal wav1,wav2,wav3 : std_logic_vector(7 downto 0); + -- watchdog + signal watchdog_cnt : std_logic_vector(3 downto 0); + signal watchdog_reset_l : std_logic; signal rom0_cs,rom1_cs : std_logic; @@ -151,323 +151,506 @@ begin rom0_cs <= '1' when dn_addr(15 downto 14) = "00" else '0'; rom1_cs <= '1' when dn_addr(15 downto 14) = "01" else '0'; --- --- video timing --- -p_hvcnt : process -begin - wait until rising_edge(clk); - if (ena_6 = '1') then - if hcnt = "111111111" then - hcnt <= "010000000"; -- 080 - else - hcnt <= hcnt +"1"; - end if; - -- hcnt 8 on circuit is 256H_L - if do_hsync then - if vcnt = "111111111" then - vcnt <= "011111000"; -- 0F8 - else - vcnt <= vcnt +"1"; - end if; - end if; - end if; -end process; + -- + -- video timing + -- + p_hvcnt : process + variable hcarry,vcarry : boolean; + begin + wait until rising_edge(clk); + if (ena_6 = '1') then + hcarry := (hcnt = "111111111"); + if hcarry then + hcnt <= "010000000"; -- 080 + else + hcnt <= hcnt +"1"; + end if; + -- hcnt 8 on circuit is 256H_L + vcarry := (vcnt = "111111111"); + if do_hsync then + if vcarry then + vcnt <= "011111000"; -- 0F8 + else + vcnt <= vcnt +"1"; + end if; + end if; + end if; + end process; -vsync <= not vcnt(8); -do_hsync <= (hcnt = "010101111"); -- 0AF + p_sync_comb : process(hcnt, vcnt) + begin + vsync <= not vcnt(8); + do_hsync <= (hcnt = "010101111"); -- 0AF + end process; -p_sync : process -begin - wait until rising_edge(clk); - if (ena_6 = '1') then + p_sync : process + begin + wait until rising_edge(clk); + if (ena_6 = '1') then + -- Timing hardware is coded differently to the real hw + -- to avoid the use of multiple clocks. Result is identical. - if (hcnt = "010001111") and not eight_sprites then -- 08F - hblank <= '1'; - elsif (hcnt = "011101111") and not eight_sprites then - hblank <= '0'; -- 0EF - elsif (hcnt = "111111111") and eight_sprites then - hblank <= '1'; - elsif (hcnt = "011111111") and eight_sprites then - hblank <= '0'; - end if; + if (hcnt = "010010111") then -- 097 + O_HBLANK <= '1'; + elsif (hcnt = "010001111") then -- 08F + hblank <= '1'; + elsif (hcnt = "011101111") then + hblank <= '0'; -- 0EF + elsif (hcnt = "011110111") then -- 0F7 + O_HBLANK <= '0'; + end if; - if do_hsync then - hsync <= '1'; - elsif (hcnt = "011001111") then -- 0CF - hsync <= '0'; - end if; + if do_hsync then + hsync <= '1'; + elsif (hcnt = "011001111") then -- 0CF + hsync <= '0'; + end if; - if do_hsync then - if (vcnt = "111101111") then -- 1EF - vblank <= '1'; - elsif (vcnt = "100001111") then -- 10F - vblank <= '0'; - end if; - end if; - end if; -end process; + if do_hsync then + if (vcnt = "111101111") then -- 1EF + vblank <= '1'; + elsif (vcnt = "100001111") then -- 10F + vblank <= '0'; + end if; + end if; + end if; + end process; --- --- cpu --- -p_irq_req_watchdog : process - variable rising_vblank : boolean; -begin - wait until rising_edge(clk); - if (ena_6 = '1') then - rising_vblank := do_hsync and (vcnt = "111101111"); -- 1EF + -- + -- cpu + -- + p_cpu_wait_comb : process(sync_bus_wreq_l) + begin + cpu_wait_l <= '1'; + if (sync_bus_wreq_l = '0') then + cpu_wait_l <= '0'; + end if; + end process; - if (control_reg(0) = '0') then - cpu_int_l <= '1'; - elsif rising_vblank then -- 1EF - cpu_int_l <= '0'; - end if; + p_irq_req_watchdog : process + variable rising_vblank : boolean; + begin + wait until rising_edge(clk); + if (ena_6 = '1') then + rising_vblank := do_hsync and (vcnt = "111101111"); -- 1EF + --rising_vblank := do_hsync; -- debug + -- interrupt 8c - -- watchdog 8c - -- note sync reset - if (reset = '1') then - watchdog_cnt <= "1111"; - elsif (iodec_wdr_l = '0') then - watchdog_cnt <= "0000"; - elsif rising_vblank then - watchdog_cnt <= watchdog_cnt + "1"; - end if; + if (control_reg(0) = '0') then + cpu_int_l <= '1'; + elsif rising_vblank then -- 1EF + cpu_int_l <= '0'; + end if; - --watchdog_reset_l <= not reset; - - watchdog_reset_l <= '1'; - if (watchdog_cnt = "1111") then - watchdog_reset_l <= '0'; - end if; - end if; -end process; - -u_cpu : entity work.T80sed -port map -( - RESET_n => watchdog_reset_l and (not reset), - CLK_n => clk, - CLKEN => hcnt(0) and ena_6, - WAIT_n => sync_bus_wreq_l, - INT_n => cpu_int_l, - NMI_n => '1', - BUSRQ_n => '1', - M1_n => cpu_m1_l, - MREQ_n => cpu_mreq_l, - IORQ_n => cpu_iorq_l, - RD_n => cpu_rd_l, - WR_n => open, - RFSH_n => cpu_rfsh_l, - HALT_n => open, - BUSAK_n => open, - A => cpu_addr, - DI => cpu_data_in, - DO => cpu_data_out -); - --- rom 0x0000 - 0x3FFF --- syncbus 0x4000 - 0x7FFF -sync_bus_cs_l <= '0' when cpu_mreq_l = '0' and cpu_rfsh_l = '1' and cpu_addr(14) = '1' else '1'; -sync_bus_wreq_l <= '0' when sync_bus_cs_l = '0' and hcnt(1) = '1' and cpu_rd_l = '0' else '1'; -sync_bus_stb <= '0' when sync_bus_cs_l = '0' and hcnt(1) = '0' else '1'; -sync_bus_r_w_l <= '0' when sync_bus_stb = '0' and cpu_rd_l = '1' else '1'; - --- --- sync bus custom ic --- -p_sync_bus_reg : process -begin - wait until rising_edge(clk); - if (ena_6 = '1') then - -- register on sync bus module that is used to store interrupt vector - if (cpu_iorq_l = '0') and (cpu_m1_l = '1') then - cpu_vec_reg <= cpu_data_out; - end if; - - -- read holding reg - if (hcnt(1 downto 0) = "01") then - sync_bus_reg <= cpu_data_in; - end if; - end if; -end process; + -- watchdog 8c + -- note sync reset + if (reset = '1') then + watchdog_cnt <= "1111"; + elsif (iodec_wdr_l = '0') then + watchdog_cnt <= "0000"; + elsif rising_vblank then + watchdog_cnt <= watchdog_cnt + "1"; + end if; --- WRITE --- out_l 0x5000 - 0x503F control space --- sn1_l 0x5040 - 0x504F sound --- sn2_l 0x5050 - 0x505F sound --- spr_l 0x5060 - 0x506F sprite --- wdr_l 0x50C0 - 0x50FF watchdog reset -iodec_out_l <= '0' when sync_bus_r_w_l = '0' and cpu_addr(15 downto 6) = X"50"&"00" else '1'; -iodec_sn1_l <= '0' when sync_bus_r_w_l = '0' and cpu_addr(15 downto 4) = X"50"&X"4" else '1'; -iodec_sn2_l <= '0' when sync_bus_r_w_l = '0' and cpu_addr(15 downto 4) = X"50"&X"5" else '1'; -iodec_spr_l <= '0' when sync_bus_r_w_l = '0' and cpu_addr(15 downto 4) = X"50"&X"6" else '1'; -iodec_wdr_l <= '0' when sync_bus_r_w_l = '0' and cpu_addr(15 downto 6) = X"50"&"11" else '1'; + watchdog_reset_l <= '1'; + if (watchdog_cnt = "1111") then + watchdog_reset_l <= '0'; + end if; --- READ --- in0_l 0x5000 - 0x503F in port 0 --- in1_l 0x5040 - 0x507F in port 1 --- dipsw_l 0x5080 - 0x50BF dip switches -iodec_in0_l <= '0' when sync_bus_r_w_l = '1' and cpu_addr(15 downto 6) = X"50"&"00" else '1'; -iodec_in1_l <= '0' when sync_bus_r_w_l = '1' and cpu_addr(15 downto 6) = X"50"&"01" else '1'; -iodec_dipsw1_l <= '0' when sync_bus_r_w_l = '1' and cpu_addr(15 downto 6) = X"50"&"10" else '1'; -iodec_dipsw2_l <= '0' when sync_bus_r_w_l = '1' and cpu_addr(15 downto 6) = X"50"&"11" else '1'; + -- simulation + -- pragma translate_off + -- synopsys translate_off + watchdog_reset_l <= not reset; -- watchdog disable + -- synopsys translate_on + -- pragma translate_on + end if; + end process; -p_control_reg : process -begin - -- 8 bit addressable latch 7K - -- (made into register) + -- other cpu signals + cpu_busrq_l <= '1'; + cpu_nmi_l <= '1'; - -- 0 interrupt ena - -- 1 sound ena - -- 2 not used - -- 3 flip - -- 4 1 player start lamp - -- 5 2 player start lamp - -- 6 coin lockout - -- 7 coin counter + p_cpu_ena : process(hcnt, ena_6) + begin + cpu_ena <= '0'; + if (ena_6 = '1') then + cpu_ena <= hcnt(0); + end if; + end process; - wait until rising_edge(clk); - if (ena_6 = '1') then - if (watchdog_reset_l = '0') then - control_reg <= (others => '0'); - elsif (iodec_out_l = '0') then - control_reg(to_integer(unsigned(cpu_addr(2 downto 0)))) <= cpu_data_out(0); - end if; - end if; -end process; + u_cpu : entity work.T80sed + port map ( + RESET_n => watchdog_reset_l, + CLK_n => clk, + CLKEN => cpu_ena, + WAIT_n => cpu_wait_l, + INT_n => cpu_int_l, + NMI_n => cpu_nmi_l, + BUSRQ_n => cpu_busrq_l, + M1_n => cpu_m1_l, + MREQ_n => cpu_mreq_l, + IORQ_n => cpu_iorq_l, + RD_n => cpu_rd_l, + WR_n => open, + RFSH_n => cpu_rfsh_l, + HALT_n => open, + BUSAK_n => open, + A => cpu_addr, + DI => cpu_data_in, + DO => cpu_data_out + ); + -- + -- primary addr decode + -- + p_mem_decode_comb : process(cpu_rfsh_l, cpu_rd_l, cpu_mreq_l, cpu_addr) + begin + -- rom 0x0000 - 0x3FFF + -- syncbus 0x4000 - 0x7FFF -cpu_data_in <= cpu_vec_reg when (cpu_iorq_l = '0') and (cpu_m1_l = '0') else - sync_bus_reg when sync_bus_wreq_l = '0' else - program_rom_dinl when cpu_addr(15 downto 14) = "00" else -- ROM at 0000 - 3fff - program_rom_dinh when cpu_addr(15 downto 14) = "10" else -- ROM at 8000 - bfff - in0 when iodec_in0_l = '0' else - in1 when iodec_in1_l = '0' else - dipsw1 when iodec_dipsw1_l = '0' else - dipsw2 when iodec_dipsw2_l = '0' else - ram_data; + -- 7M + -- 7N + sync_bus_cs_l <= '1'; +-- program_rom_cs_l <= '1'; -u_program_rom0 : work.dpram generic map (14,8) -port map -( - clock_a => clk, - wren_a => dn_wr and rom0_cs, - address_a => dn_addr(13 downto 0), - data_a => dn_data, + if (cpu_mreq_l = '0') and (cpu_rfsh_l = '1') then - clock_b => clk, - address_b => cpu_addr(13 downto 0), - q_b => program_rom_dinl -); +-- if (cpu_addr(14) = '0') and (cpu_rd_l = '0') then +-- program_rom_cs_l <= '0'; +-- end if; -u_program_rom1 : work.dpram generic map (14,8) -port map -( - clock_a => clk, - wren_a => dn_wr and rom1_cs, - address_a => dn_addr(13 downto 0), - data_a => dn_data, + if (cpu_addr(14) = '1') then + sync_bus_cs_l <= '0'; + end if; - clock_b => clk, - address_b => cpu_addr(13 downto 0), - q_b => program_rom_dinh -); + end if; + end process; + -- + -- sync bus custom ic + -- + p_sync_bus_reg : process + begin + wait until rising_edge(clk); + if (ena_6 = '1') then + -- register on sync bus module that is used to store interrupt vector + if (cpu_iorq_l = '0') and (cpu_m1_l = '1') then + cpu_vec_reg <= cpu_data_out; + end if; -ram_cs <= '1' when cpu_addr(15 downto 12) = X"4" else '0'; + -- read holding reg + if (hcnt(1 downto 0) = "01") then + sync_bus_reg <= cpu_data_in; + end if; + end if; + end process; -u_rams : work.dpram generic map (12,8) -port map -( - clock_a => clk, - enable_a => ena_6, - wren_a => not sync_bus_r_w_l and ram_cs, - address_a => cpu_addr(11 downto 0), - data_a => cpu_data_out, -- cpu only source of ram data - q_a => ram_data, + p_sync_bus_comb : process(cpu_rd_l, sync_bus_cs_l, hcnt) + begin + -- sync_bus_stb is now an active low clock enable signal + sync_bus_stb <= '1'; + sync_bus_r_w_l <= '1'; - clock_b => clk, - address_b => vram_addr(11 downto 0), - q_b => vram_data -); + if (sync_bus_cs_l = '0') and (hcnt(1) = '0') then + if (cpu_rd_l = '1') then + sync_bus_r_w_l <= '0'; + end if; + sync_bus_stb <= '0'; + end if; --- --- video subsystem --- + sync_bus_wreq_l <= '1'; + if (sync_bus_cs_l = '0') and (hcnt(1) = '1') and (cpu_rd_l = '0') then + sync_bus_wreq_l <= '0'; + end if; + end process; + -- + -- vram addr custom ic + -- + u_vram_addr : entity work.PACMAN_VRAM_ADDR + port map ( + AB => vram_addr_ab, + H256_L => hcnt(8), + H128 => hcnt(7), + H64 => hcnt(6), + H32 => hcnt(5), + H16 => hcnt(4), + H8 => hcnt(3), + H4 => hcnt(2), + H2 => hcnt(1), + H1 => hcnt(0), + V128 => vcnt(7), + V64 => vcnt(6), + V32 => vcnt(5), + V16 => vcnt(4), + V8 => vcnt(3), + V4 => vcnt(2), + V2 => vcnt(1), + V1 => vcnt(0), + FLIP => control_reg(3) + ); --- vram addr custom ic -hp <= hcnt(7 downto 3) when control_reg(3) = '0' else not hcnt(7 downto 3); -vp <= vcnt(7 downto 3) when control_reg(3) = '0' else not vcnt(7 downto 3); -vram_addr <= '0' & hcnt(2) & vp & hp when hcnt(8)='1' else - x"FF" & hcnt(6 downto 4) & hcnt(2) when hblank = '1' else - '0' & hcnt(2) & hp(3) & hp(3) & hp(3) & hp(3) & hp(0) & vp; + p_ab_mux_comb : process(hcnt, cpu_addr, vram_addr_ab) + begin + --When 2H is low, the CPU controls the bus. + if (hcnt(1) = '0') then + ab <= cpu_addr(11 downto 0); + else + ab <= vram_addr_ab; + end if; + end process; -sprite_xy_ram : work.dpram generic map (4,8) -port map -( - clock_a => CLK, - enable_a => ENA_6, - wren_a => not iodec_spr_l, - address_a => cpu_addr(3 downto 0), - data_a => cpu_data_out, + p_vram_comb : process(hcnt, cpu_addr, sync_bus_stb) + variable a,b : std_logic; + begin - clock_b => CLK, - address_b => vram_addr(3 downto 0), - q_b => sprite_xy_data -); + a := not (cpu_addr(12) or sync_bus_stb); + b := hcnt(1) and hcnt(0); + vram_l <= not (a or b); + end process; -u_video : entity work.PACMAN_VIDEO -port map -( - I_HCNT => hcnt, - I_VCNT => vcnt, - -- - vram_data => vram_data, - sprite_xy => sprite_xy_data, - -- - I_HBLANK => hblank, - I_VBLANK => vblank, - I_FLIP => control_reg(3), - O_HBLANK => O_HBLANK, + p_io_decode_comb : process(sync_bus_r_w_l, sync_bus_stb, ab, cpu_addr) + variable sel : std_logic_vector(2 downto 0); + variable dec : std_logic_vector(7 downto 0); + variable selb : std_logic_vector(1 downto 0); + variable decb : std_logic_vector(3 downto 0); + begin + -- WRITE + + -- out_l 0x5000 - 0x503F control space + + -- wr0_l 0x5040 - 0x504F sound + -- wr1_l 0x5050 - 0x505F sound + -- wr2_l 0x5060 - 0x506F sprite + + -- 0x5080 - 0x50BF unused + + -- wdr_l 0x50C0 - 0x50FF watchdog reset + + -- READ + + -- in0_l 0x5000 - 0x503F in port 0 + -- in1_l 0x5040 - 0x507F in port 1 + -- dipsw_l 0x5080 - 0x50BF dip switches + + -- 7J + dec := "11111111"; + sel := sync_bus_r_w_l & ab(7) & ab(6); + if (cpu_addr(12) = '1') and ( sync_bus_stb = '0') then + case sel is + when "000" => dec := "11111110"; + when "001" => dec := "11111101"; + when "010" => dec := "11111011"; + when "011" => dec := "11110111"; + when "100" => dec := "11101111"; + when "101" => dec := "11011111"; + when "110" => dec := "10111111"; + when "111" => dec := "01111111"; + when others => null; + end case; + end if; + iodec_out_l <= dec(0); + iodec_wdr_l <= dec(3); + + iodec_in0_l <= dec(4); + iodec_in1_l <= dec(5); + iodec_dipsw_l <= dec(6); + + -- 7M + decb := "1111"; + selb := ab(5) & ab(4); + if (dec(1) = '0') then + case selb is + when "00" => decb := "1110"; + when "01" => decb := "1101"; + when "10" => decb := "1011"; + when "11" => decb := "0111"; + when others => null; + end case; + end if; + wr0_l <= decb(0); + wr1_l <= decb(1); + wr2_l <= decb(2); + end process; + + p_control_reg : process + variable ena : std_logic_vector(7 downto 0); + begin + -- 8 bit addressable latch 7K + -- (made into register) + + -- 0 interrupt ena + -- 1 sound ena + -- 2 not used + -- 3 flip + -- 4 1 player start lamp + -- 5 2 player start lamp + -- 6 coin lockout + -- 7 coin counter + + wait until rising_edge(clk); + if (ena_6 = '1') then + ena := "00000000"; + if (iodec_out_l = '0') then + case ab(2 downto 0) is + when "000" => ena := "00000001"; + when "001" => ena := "00000010"; + when "010" => ena := "00000100"; + when "011" => ena := "00001000"; + when "100" => ena := "00010000"; + when "101" => ena := "00100000"; + when "110" => ena := "01000000"; + when "111" => ena := "10000000"; + when others => null; + end case; + end if; + + if (watchdog_reset_l = '0') then + control_reg <= (others => '0'); + else + for i in 0 to 7 loop + if (ena(i) = '1') then + control_reg(i) <= cpu_data_out(0); + end if; + end loop; + end if; + end if; + end process; + + p_db_mux_comb : process(hcnt, cpu_data_out, rams_data_out) + begin + -- simplified data source for video subsystem + -- only cpu or ram are sources of interest + if (hcnt(1) = '0') then + sync_bus_db <= cpu_data_out; + else + sync_bus_db <= rams_data_out; + end if; + end process; + + rom_data <= program_rom_dinl when cpu_addr(15) = '0' else program_rom_dinh; + rom_data_out <= rom_data(7 downto 6) & rom_data(3) & rom_data(4) & rom_data(5) & rom_data(2 downto 0) when MRTNT = '1' else rom_data; + + p_cpu_data_in_mux_comb : process(cpu_addr, cpu_iorq_l, cpu_m1_l, sync_bus_wreq_l, + iodec_in0_l, iodec_in1_l, iodec_dipsw_l, cpu_vec_reg, sync_bus_reg, rom_data_out, + rams_data_out, in0_reg, in1_reg, dipsw_reg) + begin + -- simplifed again + if (cpu_iorq_l = '0') and (cpu_m1_l = '0') then + cpu_data_in <= cpu_vec_reg; + elsif (sync_bus_wreq_l = '0') then + cpu_data_in <= sync_bus_reg; + else + if (cpu_addr(15 downto 14) = "00") then -- ROM at 0000 - 3fff + cpu_data_in <= rom_data_out; + elsif (cpu_addr(15 downto 13) = "100") then -- ROM at 8000 - 9fff + cpu_data_in <= rom_data_out; + else + cpu_data_in <= rams_data_out; + if (iodec_in0_l = '0') then cpu_data_in <= in0_reg; end if; + if (iodec_in1_l = '0') then cpu_data_in <= in1_reg; end if; + if (iodec_dipsw_l = '0') then cpu_data_in <= dipsw_reg; end if; + end if; + end if; + end process; + + u_rams : work.dpram generic map (12,8) + port map + ( + clock_a => clk, + enable_a => ena_6, + wren_a => not sync_bus_r_w_l and not vram_l, + address_a => ab(11 downto 0), + data_a => cpu_data_out, -- cpu only source of ram data + + clock_b => clk, + address_b => ab(11 downto 0), + q_b => rams_data_out + ); + + u_program_rom0 : work.dpram generic map (14,8) + port map + ( + clock_a => clk, + wren_a => dn_wr and rom0_cs, + address_a => dn_addr(13 downto 0), + data_a => dn_data, + + clock_b => clk, + address_b => cpu_addr(13 downto 0), + q_b => program_rom_dinl + ); + + u_program_rom1 : work.dpram generic map (14,8) + port map + ( + clock_a => clk, + wren_a => dn_wr and rom1_cs, + address_a => dn_addr(13 downto 0), + data_a => dn_data, + + clock_b => clk, + address_b => cpu_addr(13 downto 0), + q_b => program_rom_dinh + ); + + -- + -- video subsystem + -- + u_video : entity work.PACMAN_VIDEO + generic map ( + MRTNT => MRTNT + ) + port map ( + I_HCNT => hcnt, + I_VCNT => vcnt, + -- + I_AB => ab, + I_DB => sync_bus_db, + -- + I_HBLANK => hblank, + I_VBLANK => vblank, + I_FLIP => control_reg(3), + I_WR2_L => wr2_l, -- dn_addr => dn_addr, dn_data => dn_data, dn_wr => dn_wr, - -- - O_RED => O_VIDEO_R, - O_GREEN => O_VIDEO_G, - O_BLUE => O_VIDEO_B, - -- - ENA_6 => ena_6, - CLK => clk -); + -- + O_RED => O_VIDEO_R, + O_GREEN => O_VIDEO_G, + O_BLUE => O_VIDEO_B, + -- + ENA_6 => ena_6, + CLK => clk + ); -O_HSYNC <= hSync; -O_VSYNC <= vSync; -O_VBLANK <= vblank; + O_HSYNC <= hSync; + O_VSYNC <= vSync; --- --- --- audio subsystem --- -u_audio : entity work.PACMAN_AUDIO -port map ( - I_HCNT => hcnt, - -- - I_AB => cpu_addr(11 downto 0), - I_DB => cpu_data_out, - -- - I_WR1_L => iodec_sn2_l, - I_WR0_L => iodec_sn1_l, - I_SOUND_ON => control_reg(1), - -- - dn_addr => dn_addr, - dn_data => dn_data, - dn_wr => dn_wr, - -- - O_AUDIO => O_AUDIO, - ENA_6 => ena_6, - CLK => clk -); + --O_HBLANK <= hblank; + O_VBLANK <= vblank; + + -- + -- + -- audio subsystem + -- + u_audio : entity work.PACMAN_AUDIO + port map ( + I_HCNT => hcnt, + -- + I_AB => ab, + I_DB => sync_bus_db, + -- + I_WR1_L => wr1_l, + I_WR0_L => wr0_l, + I_SOUND_ON => control_reg(1), + -- + dn_addr => dn_addr, + dn_data => dn_data, + dn_wr => dn_wr, + -- + O_AUDIO => O_AUDIO, + ENA_6 => ena_6, + CLK => clk + ); end RTL; diff --git a/pacman_video.vhd b/pacman_video.vhd index 2371cf0..65527bf 100644 --- a/pacman_video.vhd +++ b/pacman_video.vhd @@ -38,7 +38,6 @@ -- -- Revision list -- --- version 004 Refactoring, 8 sprite support by Sorgelig -- version 003 Jan 2006 release, general tidy up -- version 001 initial release -- @@ -47,36 +46,39 @@ library ieee; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; +library UNISIM; + entity PACMAN_VIDEO is - generic( - alt_transp : boolean := false - ); - port ( - I_HCNT : in std_logic_vector(8 downto 0); - I_VCNT : in std_logic_vector(8 downto 0); - -- - vram_data : in std_logic_vector(7 downto 0); - sprite_xy : in std_logic_vector(7 downto 0); - -- - I_HBLANK : in std_logic; - I_VBLANK : in std_logic; - I_FLIP : in std_logic; - O_HBLANK : out std_logic; - -- - dn_addr : in std_logic_vector(15 downto 0); - dn_data : in std_logic_vector(7 downto 0); - dn_wr : in std_logic; - -- - O_RED : out std_logic_vector(2 downto 0); - O_GREEN : out std_logic_vector(2 downto 0); - O_BLUE : out std_logic_vector(1 downto 0); - ENA_6 : in std_logic; - CLK : in std_logic - ); +generic ( + MRTNT : std_logic := '0' -- 1 to descramble Mr TNT ROMs, 0 otherwise +); +port ( + I_HCNT : in std_logic_vector(8 downto 0); + I_VCNT : in std_logic_vector(8 downto 0); + -- + I_AB : in std_logic_vector(11 downto 0); + I_DB : in std_logic_vector( 7 downto 0); + -- + I_HBLANK : in std_logic; + I_VBLANK : in std_logic; + I_FLIP : in std_logic; + I_WR2_L : in std_logic; + -- + dn_addr : in std_logic_vector(15 downto 0); + dn_data : in std_logic_vector(7 downto 0); + dn_wr : in std_logic; + -- + O_RED : out std_logic_vector(2 downto 0); + O_GREEN : out std_logic_vector(2 downto 0); + O_BLUE : out std_logic_vector(1 downto 0); + ENA_6 : in std_logic; + CLK : in std_logic +); end; architecture RTL of PACMAN_VIDEO is + signal sprite_xy_ram_temp : std_logic_vector(7 downto 0); signal dr : std_logic_vector(7 downto 0); signal char_reg : std_logic_vector(7 downto 0); @@ -84,20 +86,19 @@ architecture RTL of PACMAN_VIDEO is signal char_match_reg : std_logic; signal char_hblank_reg : std_logic; signal char_hblank_reg_t1 : std_logic; - signal sprite_data : std_logic_vector(7 downto 0); + signal db_reg : std_logic_vector(7 downto 0); signal xflip : std_logic; signal yflip : std_logic; signal obj_on : std_logic; - signal obj_on2 : std_logic; signal ca : std_logic_vector(12 downto 0); + signal char_rom_5ef_dout : std_logic_vector(7 downto 0); signal char_rom_5ef_buf : std_logic_vector(7 downto 0); signal shift_regl : std_logic_vector(3 downto 0); signal shift_regu : std_logic_vector(3 downto 0); signal shift_op : std_logic_vector(1 downto 0); - signal shift_op_t1 : std_logic_vector(1 downto 0); signal shift_sel : std_logic_vector(1 downto 0); signal vout_obj_on : std_logic; @@ -107,14 +108,15 @@ architecture RTL of PACMAN_VIDEO is signal vout_hblank_t1 : std_logic; signal vout_db : std_logic_vector(4 downto 0); - signal sprite_ram_ip : std_logic_vector(5 downto 0); - signal sprite_ram_op : std_logic_vector(5 downto 0); - signal sprite_addr : std_logic_vector(7 downto 0); - signal sprite_addr_t1 : std_logic_vector(7 downto 0); + signal cntr_ld : std_logic; + signal sprite_ram_ip : std_logic_vector(3 downto 0); + signal sprite_ram_op : std_logic_vector(3 downto 0); + signal ra : std_logic_vector(7 downto 0); + signal ra_t1 : std_logic_vector(7 downto 0); signal lut_4a : std_logic_vector(7 downto 0); signal lut_4a_t1 : std_logic_vector(7 downto 0); - signal sprite_ram_reg : std_logic_vector(5 downto 0); + signal sprite_ram_reg : std_logic_vector(3 downto 0); signal video_op_sel : std_logic; signal final_col : std_logic_vector(3 downto 0); @@ -125,110 +127,170 @@ architecture RTL of PACMAN_VIDEO is signal rom4a_cs : std_logic; begin + prom_cs <= '1' when dn_addr(15 downto 14) = "11" else '0'; gfx_cs <= '1' when dn_addr(15 downto 13) = "100" else '0'; -dr <= not sprite_xy when I_HBLANK = '1' else "11111111"; -- pull ups on board + -- ram enable is low when HBLANK_L is 0 (for sprite access) or + -- 2H is low (for cpu writes) + -- we can simplify this + dr <= not sprite_xy_ram_temp when I_HBLANK = '1' else "11111111"; -- pull ups on board -p_char_regs : process - variable sum : std_logic_vector(8 downto 0); - variable match : std_logic; -begin - wait until rising_edge (CLK); - if (I_HCNT(2 downto 0) = "011") and (ENA_6 = '1') then -- rising 4h + sprite_xy_ram : work.dpram generic map (4,8) + port map + ( + clock_a => CLK, + enable_a => ENA_6, + wren_a => not I_WR2_L, + address_a => I_AB(3 downto 0), + data_a => I_DB, - -- 1f, 2f - sum := (I_VCNT(7 downto 0) & '1') + (dr & not I_HBLANK); + clock_b => CLK, + address_b => I_AB(3 downto 0), + q_b => sprite_xy_ram_temp + ); - -- 3e - match := '0'; + p_char_regs : process + variable inc : std_logic; + variable sum : std_logic_vector(8 downto 0); + variable match : std_logic; + begin + wait until rising_edge (CLK); + if (I_HCNT(2 downto 0) = "011") and (ENA_6 = '1') then -- rising 4h + inc := (not I_HBLANK); - if (sum(8 downto 5) = "1111") then - match := '1'; + -- 1f, 2f + sum := (I_VCNT(7 downto 0) & '1') + (dr & inc); + + -- 3e + match := '0'; + + if (sum(8 downto 5) = "1111") then + match := '1'; + end if; + + -- 1h + char_sum_reg <= sum(4 downto 1); + char_match_reg <= match; + char_hblank_reg <= I_HBLANK; + + -- 4d + db_reg <= I_DB; -- character reg end if; + end process; - -- 1h - char_sum_reg <= sum(4 downto 1); - char_match_reg <= match; - char_hblank_reg <= I_HBLANK; - - -- 4d - sprite_data <= vram_data; -- character reg - end if; -end process; - -xflip <= I_FLIP when char_hblank_reg = '0' else sprite_data(1); -yflip <= I_FLIP when char_hblank_reg = '0' else sprite_data(0); - -obj_on <= char_match_reg or I_HCNT(8); -- 256h not 256h_l - -ca(12) <= char_hblank_reg; -ca(11 downto 6) <= sprite_data(7 downto 2); -ca(5) <= sprite_data(1) when char_hblank_reg = '0' else char_sum_reg(3) xor xflip; -ca(4) <= sprite_data(0) when char_hblank_reg = '0' else I_HCNT(3); -ca(3) <= I_HCNT(2) xor yflip; -ca(2) <= char_sum_reg(2) xor xflip; -ca(1) <= char_sum_reg(1) xor xflip; -ca(0) <= char_sum_reg(0) xor xflip; - --- char roms -char_rom_5ef : work.dpram generic map (13,8) -port map -( - clock_a => clk, - wren_a => dn_wr and gfx_cs, - address_a => dn_addr(12 downto 0), - data_a => dn_data, - - clock_b => clk, - address_b => ca, - q_b => char_rom_5ef_buf -); - -p_char_shift : process -begin - -- 4 bit shift req - wait until rising_edge (CLK); - if (ENA_6 = '1') then - case shift_sel is - when "00" => null; - - when "01" => shift_regu <= '0' & shift_regu(3 downto 1); - shift_regl <= '0' & shift_regl(3 downto 1); - - when "10" => shift_regu <= shift_regu(2 downto 0) & '0'; - shift_regl <= shift_regl(2 downto 0) & '0'; - - when "11" => shift_regu <= char_rom_5ef_buf(7 downto 4); -- load - shift_regl <= char_rom_5ef_buf(3 downto 0); - when others => null; - end case; - end if; -end process; - -shift_sel(0) <= I_HCNT(0) and I_HCNT(1) when vout_yflip = '0' else '1'; -shift_sel(1) <= '1' when vout_yflip = '0' else I_HCNT(0) and I_HCNT(1); -shift_op(0) <= shift_regl(3) when vout_yflip = '0' else shift_regl(0); -shift_op(1) <= shift_regu(3) when vout_yflip = '0' else shift_regu(0); - -p_video_out_reg : process -begin - wait until rising_edge (CLK); - if (ENA_6 = '1') then - if (I_HCNT(2 downto 0) = "111") then - vout_obj_on <= obj_on; - vout_yflip <= yflip; - vout_hblank <= I_HBLANK; - vout_db(4 downto 0) <= vram_data(4 downto 0); -- colour reg - end if; - - if I_HCNT(3 downto 0) = "0111" and (vout_hblank='1' or I_HBLANK='1' or vout_obj_on='0') then - sprite_addr <= dr; + p_flip_comb : process(char_hblank_reg, I_FLIP, db_reg) + begin + if (char_hblank_reg = '0') then + xflip <= I_FLIP; + yflip <= I_FLIP; else - sprite_addr <= sprite_addr + "1"; + xflip <= db_reg(1); + yflip <= db_reg(0); end if; - end if; -end process; + end process; + + p_char_addr_comb : process(db_reg, I_HCNT, + char_match_reg, char_sum_reg, char_hblank_reg, + xflip, yflip) + begin + obj_on <= char_match_reg or I_HCNT(8); -- 256h not 256h_l + + ca(12) <= char_hblank_reg; + ca(11 downto 6) <= db_reg(7 downto 2); + + -- 2h, 4e + if (char_hblank_reg = '0') then + ca(5) <= db_reg(1); + ca(4) <= db_reg(0); + else + ca(5) <= char_sum_reg(3) xor xflip; + ca(4) <= I_HCNT(3); + end if; + + ca(3) <= I_HCNT(2) xor yflip; + ca(1) <= char_sum_reg(1) xor xflip; + + -- descramble ROMs for Mr TNT (swap address lines A0 and A2) + if MRTNT = '1' then + ca(2) <= char_sum_reg(0) xor xflip; + ca(0) <= char_sum_reg(2) xor xflip; + else + ca(2) <= char_sum_reg(2) xor xflip; + ca(0) <= char_sum_reg(0) xor xflip; + end if; + end process; + + + -- descramble ROMs for Mr TNT (swap data lines D4 and D6) + char_rom_5ef_dout <= char_rom_5ef_buf(7) & char_rom_5ef_buf(4) & char_rom_5ef_buf(5) & char_rom_5ef_buf(6) & char_rom_5ef_buf(3 downto 0) when MRTNT = '1' else char_rom_5ef_buf; + + -- char roms + char_rom_5ef : work.dpram generic map (13,8) + port map + ( + clock_a => clk, + wren_a => dn_wr and gfx_cs, + address_a => dn_addr(12 downto 0), + data_a => dn_data, + + clock_b => clk, + address_b => ca, + q_b => char_rom_5ef_buf + ); + + p_char_shift : process + begin + -- 4 bit shift req + wait until rising_edge (CLK); + if (ENA_6 = '1') then + case shift_sel is + when "00" => null; + + when "01" => shift_regu <= '0' & shift_regu(3 downto 1); + shift_regl <= '0' & shift_regl(3 downto 1); + + when "10" => shift_regu <= shift_regu(2 downto 0) & '0'; + shift_regl <= shift_regl(2 downto 0) & '0'; + + when "11" => shift_regu <= char_rom_5ef_dout(7 downto 4); -- load + shift_regl <= char_rom_5ef_dout(3 downto 0); + when others => null; + end case; + end if; + end process; + + p_char_shift_comb : process(I_HCNT, vout_yflip, shift_regu, shift_regl) + variable ip : std_logic; + begin + ip := I_HCNT(0) and I_HCNT(1); + if (vout_yflip = '0') then + + shift_sel(0) <= ip; + shift_sel(1) <= '1'; + shift_op(0) <= shift_regl(3); + shift_op(1) <= shift_regu(3); + else + + shift_sel(0) <= '1'; + shift_sel(1) <= ip; + shift_op(0) <= shift_regl(0); + shift_op(1) <= shift_regu(0); + end if; + end process; + + p_video_out_reg : process + begin + wait until rising_edge (CLK); + if (ENA_6 = '1') then + if (I_HCNT(2 downto 0) = "111") then + vout_obj_on <= obj_on; + vout_yflip <= yflip; + vout_hblank <= I_HBLANK; + vout_db(4 downto 0) <= I_DB(4 downto 0); -- colour reg + end if; + end if; + end process; rom4a_cs <= '1' when dn_addr(9 downto 8) = "01" else '0'; @@ -248,49 +310,78 @@ port map ); + cntr_ld <= '1' when (I_HCNT(3 downto 0) = "0111") and (vout_hblank='1' or vout_obj_on='0') else '0'; + p_ra_cnt : process + begin + wait until rising_edge (CLK); + if (ENA_6 = '1') then + if (cntr_ld = '1') then + ra <= dr; + else + ra <= ra + "1"; + end if; + end if; + end process; -u_sprite_ram : work.dpram generic map (8,6) -port map -( - clock_a => CLK, - enable_a => ENA_6, - wren_a => vout_obj_on_t1, - address_a => sprite_addr_t1, - data_a => sprite_ram_ip, + u_sprite_ram : work.dpram generic map (8,4) + port map + ( + clock_a => CLK, + enable_a => ENA_6, + wren_a => vout_obj_on_t1, + address_a => ra_t1, + data_a => sprite_ram_ip, + + clock_b => CLK, + enable_b => ENA_6, + address_b => ra, + q_b => sprite_ram_op + ); - clock_b => CLK, - enable_b => ENA_6, - address_b => sprite_addr, - q_b => sprite_ram_op -); + sprite_ram_reg <= sprite_ram_op when vout_obj_on_t1 = '1' else "0000"; + video_op_sel <= '1' when not (sprite_ram_reg = "0000") else '0'; -sprite_ram_reg <= sprite_ram_op when vout_obj_on_t1 = '1' else "000000"; -video_op_sel <= '0' when alt_transp and (sprite_ram_reg(1 downto 0) = "00") else - '0' when not alt_transp and (sprite_ram_reg(5 downto 2) = "0000") else - '1'; + p_sprite_ram_ip_reg : process + begin + wait until rising_edge (CLK); + if (ENA_6 = '1') then + ra_t1 <= ra; + vout_obj_on_t1 <= vout_obj_on; + vout_hblank_t1 <= vout_hblank; + lut_4a_t1 <= lut_4a; + end if; + end process; -p_sprite_ram_ip_reg : process -begin - wait until rising_edge (CLK); - if (ENA_6 = '1') then - sprite_addr_t1 <= sprite_addr; - vout_obj_on_t1 <= vout_obj_on; - vout_hblank_t1 <= vout_hblank; - lut_4a_t1 <= lut_4a; - shift_op_t1 <= shift_op; - end if; -end process; + p_sprite_ram_ip_comb : process(vout_hblank_t1, video_op_sel, sprite_ram_reg, lut_4a_t1) + begin + -- 3a + if (vout_hblank_t1 = '0') then + sprite_ram_ip <= (others => '0'); + else + if (video_op_sel = '1') then + sprite_ram_ip <= sprite_ram_reg; + else + sprite_ram_ip <= lut_4a_t1(3 downto 0); + end if; + end if; + end process; -sprite_ram_ip <= (others => '0') when vout_hblank_t1 = '0' else - sprite_ram_reg when video_op_sel = '1' else - lut_4a_t1(3 downto 0) & shift_op_t1; + p_video_op_comb : process(vout_hblank, I_VBLANK, video_op_sel, sprite_ram_reg, lut_4a) + begin + -- 3b + if (vout_hblank = '1') or (I_VBLANK = '1') then + final_col <= (others => '0'); + else + if (video_op_sel = '1') then + final_col <= sprite_ram_reg; -- sprite + else + final_col <= lut_4a(3 downto 0); + end if; + end if; + end process; -final_col <= (others => '0') when (vout_hblank = '1') or (I_VBLANK = '1') else - sprite_ram_reg(5 downto 2) when video_op_sel = '1' else - lut_4a(3 downto 0); - --- assign video outputs from color LUT PROM + -- assign video outputs from color LUT PROM rom7_cs <= '1' when dn_addr(9 downto 4) = "110000" else '0'; col_rom_7f : work.dpram generic map (4,8) @@ -308,6 +399,4 @@ final_col <= (others => '0') when (vout_hblank = '1') or (I_VBLANK = '1') else q_b(7 downto 6) => O_BLUE ); -O_HBLANK <= vout_hblank and vout_hblank_t1; - end architecture; diff --git a/pacman_vram_addr.vhd b/pacman_vram_addr.vhd new file mode 100644 index 0000000..fb14226 --- /dev/null +++ b/pacman_vram_addr.vhd @@ -0,0 +1,273 @@ +-- +-- A simulation model of Pacman hardware +-- Copyright (c) MikeJ & CarlW - January 2006 +-- +-- 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 permission. +-- +-- THIS CODE 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. +-- +-- You are responsible for any legal issues arising from your use of this code. +-- +-- The latest version of this file can be found at: www.fpgaarcade.com +-- +-- Email pacman@fpgaarcade.com +-- +-- Revision list +-- +-- version 003 Jan 2006 release, general tidy up +-- version 001 initial release +-- +library ieee; + use ieee.std_logic_1164.all; + use ieee.std_logic_unsigned.all; + use ieee.numeric_std.all; + +entity X74_157 is + port ( + Y : out std_logic_vector (3 downto 0); + B : in std_logic_vector (3 downto 0); + A : in std_logic_vector (3 downto 0); + G : in std_logic; + S : in std_logic + ); +end; + +architecture RTL of X74_157 is +begin + p_y_comb : process(S,G,A,B) + begin + for i in 0 to 3 loop + -- quad 2 line to 1 line mux (true logic) + if (G = '1') then + Y(i) <= '0'; + else + if (S = '0') then + Y(i) <= A(i); + else + Y(i) <= B(i); + end if; + end if; + end loop; + end process; +end RTL; + +library ieee; + use ieee.std_logic_1164.all; + use ieee.std_logic_arith.all; + use ieee.std_logic_unsigned.all; + +entity X74_257 is + port ( + Y : out std_logic_vector (3 downto 0); + B : in std_logic_vector (3 downto 0); + A : in std_logic_vector (3 downto 0); + S : in std_logic + ); +end; + +architecture RTL of X74_257 is +signal ab : std_logic_vector (3 downto 0); +begin + + Y <= ab; -- no tristate + p_ab : process(S,A,B) + begin + for i in 0 to 3 loop + if (S = '0') then + AB(i) <= A(i); + else + AB(i) <= B(i); + end if; + end loop; + end process; +end RTL; + +library ieee; + use ieee.std_logic_1164.all; + use ieee.std_logic_unsigned.all; + use ieee.numeric_std.all; + +entity PACMAN_VRAM_ADDR is + port ( + AB : out std_logic_vector (11 downto 0); + H256_L : in std_logic; + H128 : in std_logic; + H64 : in std_logic; + H32 : in std_logic; + H16 : in std_logic; + H8 : in std_logic; + H4 : in std_logic; + H2 : in std_logic; + H1 : in std_logic; + V128 : in std_logic; + V64 : in std_logic; + V32 : in std_logic; + V16 : in std_logic; + V8 : in std_logic; + V4 : in std_logic; + V2 : in std_logic; + V1 : in std_logic; + FLIP : in std_logic + ); +end; + +architecture RTL of PACMAN_VRAM_ADDR is + +signal v128p : std_logic; +signal v64p : std_logic; +signal v32p : std_logic; +signal v16p : std_logic; +signal v8p : std_logic; +signal h128p : std_logic; +signal h64p : std_logic; +signal h32p : std_logic; +signal h16p : std_logic; +signal h8p : std_logic; +signal sel : std_logic; +signal y157 : std_logic_vector (11 downto 0); + +component X74_157 + port ( + Y : out std_logic_vector (3 downto 0); + B : in std_logic_vector (3 downto 0); + A : in std_logic_vector (3 downto 0); + G : in std_logic; + S : in std_logic + ); +end component; + +component X74_257 + port ( + Y : out std_logic_vector (3 downto 0); + B : in std_logic_vector (3 downto 0); + A : in std_logic_vector (3 downto 0); + S : in std_logic + ); +end component; + +begin + p_vp_comb : process(FLIP, V8, V16, V32, V64, V128) + begin + v128p <= FLIP xor V128; + v64p <= FLIP xor V64; + v32p <= FLIP xor V32; + v16p <= FLIP xor V16; + v8p <= FLIP xor V8; + end process; + + p_hp_comb : process(FLIP, H8, H16, H32, H64, H128) + begin + H128P <= FLIP xor H128; + H64P <= FLIP xor H64; + H32P <= FLIP xor H32; + H16P <= FLIP xor H16; + H8P <= FLIP xor H8; + end process; + + p_sel : process(H16, H32, H64) + begin + sel <= not((H32 xor H16) or (H32 xor H64)); + end process; + + --p_oe257 : process(H2) + --begin + -- oe <= not(H2); + --end process; + + U6 : X74_157 + port map( + Y => y157(11 downto 8), + B(3) => '0', + B(2) => H4, + B(1) => h64p, + B(0) => h64p, + A => "1111", + G => '0', + S => sel + ); + + U5 : X74_157 + port map( + Y => y157(7 downto 4), + B(3) => h64p, + B(2) => h64p, + B(1) => h8p, + B(0) => v128p, + A => "1111", + G => '0', + S => sel + ); + + U4 : X74_157 + port map( + Y => y157(3 downto 0), + B(3) => v64p, + B(2) => v32p, + B(1) => v16p, + B(0) => v8p, + A(3) => H64, + A(2) => H32, + A(1) => H16, + A(0) => H4, + G => '0', + S => sel + ); + + U3 : X74_257 + port map( + Y => AB(11 downto 8), + B(3) => '0', + B(2) => H4, + B(1) => v128p, + B(0) => v64p, + A => y157(11 downto 8), + S => H256_L + ); + + U2 : X74_257 + port map( + Y => AB(7 downto 4), + B(3) => v32p, + B(2) => v16p, + B(1) => v8p, + B(0) => h128p, + A => y157(7 downto 4), + S => H256_L + ); + + U1 : X74_257 + port map( + Y => AB(3 downto 0), + B(3) => h64p, + B(2) => h32p, + B(1) => h16p, + B(0) => h8p, + A => y157(3 downto 0), + S => H256_L + ); + +end RTL;