Revision 39
Added by markw over 11 years ago
common/a8core/address_decoder.vhdl | ||
---|---|---|
|
||
ANTIC_ADDR : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
|
||
ANTIC_FETCH : IN STD_LOGIC;
|
||
antic_refresh : in std_logic; -- use for sdram refresh (sdram needs more, but this is a start)
|
||
|
||
DMA_ADDR : in std_logic_vector(23 downto 0);
|
||
DMA_FETCH : in std_logic;
|
||
... | ... | |
SDRAM_WRITE_EN : out std_logic;
|
||
--SDRAM_REQUEST : out std_logic; -- Toggle this to issue a new request
|
||
SDRAM_REQUEST : out std_logic; -- Usual pattern
|
||
SDRAM_REFRESH : out std_logic;
|
||
|
||
--SDRAM_REPLY : in std_logic; -- This matches the request once complete
|
||
SDRAM_REQUEST_COMPLETE : in std_logic;
|
||
... | ... | |
|
||
SDRAM_REQUEST <= sdram_chip_select;
|
||
--SDRAM_REQUEST <= sdram_request_next;
|
||
SDRAM_REFRESH <= '0'; --fetch_wait_reg(7); -- TODO, BROKEN! antic_refresh;
|
||
SDRAM_READ_EN <= not(write_enable_next);
|
||
SDRAM_WRITE_EN <= write_enable_next;
|
||
|
common/a8core/antic.vhdl | ||
---|---|---|
END antic;
|
||
|
||
ARCHITECTURE vhdl OF antic IS
|
||
component enable_divider IS
|
||
generic(COUNT : natural := 1);
|
||
PORT
|
||
(
|
||
CLK : IN STD_LOGIC;
|
||
RESET_N : IN STD_LOGIC;
|
||
ENABLE_IN : IN STD_LOGIC;
|
||
|
||
ENABLE_OUT : OUT STD_LOGIC
|
||
);
|
||
END component;
|
||
|
||
COMPONENT complete_address_decoder IS
|
||
generic (width : natural := 1);
|
||
PORT
|
||
... | ... | |
-- Colour clock (3.57MHz for PAL)
|
||
-- TODO - allow double for 640 pixel width and quadruple for 1280 pixel width)
|
||
-- TODO - allow other clocks for driving VGA (mostly higher dot clock + line doubling (buffer between antic and gtia??))
|
||
--enable_colour_clock_div : enable_divider
|
||
--generic map (COUNT=>7)
|
||
--port map(clk=>clk,reset_n=>reset_n,enable_in=>'1',enable_out=>enable_colour_clock);
|
||
|
||
colour_clock_count_reg_topthree <= colour_clock_count_reg(cycle_length_bits-1 downto cycle_length_bits-3);
|
||
process(colour_clock_count_reg, colour_clock_count_reg_topthree, ANTIC_ENABLE_179)
|
||
... | ... | |
end case;
|
||
end process;
|
||
|
||
--enable_dma_clock_div : enable_divider
|
||
-- generic map (COUNT=>2)
|
||
-- port map(clk=>clk,reset_n=>reset_n,enable_in=>colour_clock_selected,enable_out=>enable_dma);
|
||
|
||
-- Counters (memory address for data, memory address for display list)
|
||
antic_counter_memory_scan : antic_counter
|
||
generic map (STORE_WIDTH=>16, COUNT_WIDTH=>12)
|
||
... | ... | |
begin
|
||
increment_refresh_count <= '0';
|
||
refresh_pending_next <= refresh_pending_reg;
|
||
refresh_fetch_next <= not(memory_ready_antic) and refresh_fetch_reg;
|
||
refresh_fetch_next <= '0';
|
||
|
||
if (colour_clock_1x = '1') then
|
||
-- do pending refresh once we have a spare cycle
|
||
... | ... | |
-- wsync write takes 1 cycle to assert rdy
|
||
-- TODO - revisit antic delays in terms of cpu cycles
|
||
wsync_delay : delay_line
|
||
generic map (COUNT=>cycle_length+cycle_length/2)
|
||
--generic map (COUNT=>cycle_length+cycle_length/2)
|
||
generic map (COUNT=>cycle_length+cycle_length-2) -- TODO
|
||
port map (clk=>clk,sync_reset=>'0',data_in=>wsync_write,enable=>'1',reset_n=>reset_n,data_out=>wsync_delayed_write);
|
||
|
||
-- dmactl takes 1 cycle to be applied - NO IT DOES NOT - TODO FIXME
|
||
... | ... | |
|
||
antic_ready <= not(wsync_reg);
|
||
|
||
dma_fetch_out <= refresh_fetch_reg or (allow_real_dma_reg and dma_fetch_reg);
|
||
dma_fetch_out <= allow_real_dma_reg and dma_fetch_reg;
|
||
dma_address_out <= dma_address_reg;
|
||
|
||
refresh_out <= refresh_fetch_reg;
|
common/a8core/atari800core.vhd | ||
---|---|---|
(
|
||
cycle_length : integer := 16; -- or 32...
|
||
video_bits : integer := 8;
|
||
palette : integer :=1 -- 0:gtia colour on VGA_B, 1:altirra, 2:laoo
|
||
palette : integer :=1 -- 0:gtia colour on VIDEO_B, 1:altirra, 2:laoo
|
||
);
|
||
PORT
|
||
(
|
||
... | ... | |
RESET_N : IN STD_LOGIC;
|
||
|
||
-- VIDEO OUT - PAL/NTSC, original Atari timings approx (may be higher res)
|
||
VGA_VS : OUT STD_LOGIC;
|
||
VGA_HS : OUT STD_LOGIC;
|
||
VGA_B : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VGA_G : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VGA_R : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VIDEO_VS : OUT STD_LOGIC;
|
||
VIDEO_HS : OUT STD_LOGIC;
|
||
VIDEO_B : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VIDEO_G : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VIDEO_R : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VIDEO_BLANK : out std_logic;
|
||
VIDEO_BURST : out std_logic;
|
||
VIDEO_START_OF_FIELD : out std_logic;
|
||
VIDEO_ODD_LINE : out std_logic;
|
||
|
||
-- AUDIO OUT - Pokey/GTIA 1-bit and Covox all mixed
|
||
-- TODO - choose stereo/mono pokey
|
||
... | ... | |
|
||
-- ANTIC lightpen
|
||
ANTIC_LIGHTPEN : IN std_logic;
|
||
ANTIC_REFRESH : out STD_LOGIC; -- 1 cycle high when antic doing refresh cycle..., propose locking out for the next 'cycle_length'
|
||
|
||
-----------------------
|
||
-- After here all FPGA implementation specific
|
||
... | ... | |
SDRAM_ADDR : out STD_LOGIC_VECTOR(22 DOWNTO 0);
|
||
SDRAM_DO : in STD_LOGIC_VECTOR(31 DOWNTO 0);
|
||
|
||
-- ANTIC refresh cycles
|
||
-- TODO, expose a better way...
|
||
SDRAM_REFRESH : out STD_LOGIC;
|
||
|
||
RAM_ADDR : OUT STD_LOGIC_VECTOR(18 DOWNTO 0);
|
||
RAM_DO : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
|
||
RAM_REQUEST : OUT STD_LOGIC;
|
||
... | ... | |
SIGNAL ANTIC_HIGHRES_COLOUR_CLOCK_OUT : STD_LOGIC;
|
||
SIGNAL ANTIC_ORIGINAL_COLOUR_CLOCK_OUT : STD_LOGIC;
|
||
SIGNAL ANTIC_RDY : STD_LOGIC;
|
||
SIGNAL ANTIC_REFRESH : STD_LOGIC;
|
||
SIGNAL ANTIC_WRITE_ENABLE : STD_LOGIC;
|
||
SIGNAL BREAK_PRESSED : STD_LOGIC;
|
||
signal hcount_temp : std_logic_vector(7 downto 0);
|
||
signal vcount_temp : std_logic_vector(8 downto 0);
|
||
signal ANTIC_REFRESH_CYCLE : STD_LOGIC;
|
||
|
||
-- GTIA
|
||
SIGNAL GTIA_SOUND : STD_LOGIC;
|
||
... | ... | |
signal COLOUR : std_logic_vector(7 downto 0);
|
||
|
||
-- GTIA PALETTE
|
||
signal VGA_R_WIDE : std_logic_vector(7 downto 0);
|
||
signal VGA_G_WIDE : std_logic_vector(7 downto 0);
|
||
signal VGA_B_WIDE : std_logic_vector(7 downto 0);
|
||
signal VIDEO_R_WIDE : std_logic_vector(7 downto 0);
|
||
signal VIDEO_G_WIDE : std_logic_vector(7 downto 0);
|
||
signal VIDEO_B_WIDE : std_logic_vector(7 downto 0);
|
||
|
||
-- CPU
|
||
SIGNAL CPU_6502_RESET : STD_LOGIC;
|
||
... | ... | |
RESET_N => RESET_N,
|
||
MEMORY_READY_CPU => MEMORY_READY_CPU,
|
||
MEMORY_READY_ANTIC => MEMORY_READY_ANTIC,
|
||
ANTIC_REFRESH => ANTIC_REFRESH_CYCLE,
|
||
PAUSE_6502 => HALT,
|
||
THROTTLE_COUNT_6502 => THROTTLE_COUNT_6502,
|
||
ANTIC_ENABLE_179 => ANTIC_ENABLE_179,
|
||
... | ... | |
dma_fetch_out => ANTIC_FETCH,
|
||
hcount_out => hcount_temp,
|
||
vcount_out => vcount_temp,
|
||
refresh_out => ANTIC_REFRESH,
|
||
refresh_out => ANTIC_REFRESH_CYCLE,
|
||
AN => ANTIC_AN,
|
||
DATA_OUT => ANTIC_DO,
|
||
dma_address_out => ANTIC_ADDR);
|
||
... | ... | |
|
||
pokey2 : entity work.pokey
|
||
PORT MAP(CLK => CLK,
|
||
CPU_MEMORY_READY => MEMORY_READY_CPU,
|
||
ANTIC_MEMORY_READY => MEMORY_READY_ANTIC,
|
||
ENABLE_179 => ENABLE_179_MEMWAIT,
|
||
WR_EN => POKEY2_WRITE_ENABLE,
|
||
RESET_N => RESET_N,
|
||
ADDR => PBI_ADDR_INT(3 DOWNTO 0),
|
||
... | ... | |
CPU_FETCH => CPU_FETCH,
|
||
CPU_WRITE_N => R_W_N,
|
||
ANTIC_FETCH => ANTIC_FETCH,
|
||
antic_refresh => ANTIC_REFRESH,
|
||
DMA_FETCH => DMA_FETCH,
|
||
DMA_READ_ENABLE => DMA_READ_ENABLE,
|
||
DMA_32BIT_WRITE_ENABLE => DMA_32BIT_WRITE_ENABLE,
|
||
... | ... | |
SDRAM_READ_EN => SDRAM_READ_ENABLE,
|
||
SDRAM_WRITE_EN => SDRAM_WRITE_ENABLE,
|
||
SDRAM_REQUEST => SDRAM_REQUEST,
|
||
SDRAM_REFRESH => SDRAM_REFRESH,
|
||
MEMORY_DATA => MEMORY_DATA,
|
||
PBI_ADDR => PBI_ADDR_INT,
|
||
RAM_ADDR => RAM_ADDR,
|
||
... | ... | |
|
||
pokey1 : entity work.pokey
|
||
PORT MAP(CLK => CLK,
|
||
CPU_MEMORY_READY => MEMORY_READY_CPU,
|
||
ANTIC_MEMORY_READY => MEMORY_READY_ANTIC,
|
||
ENABLE_179 => ENABLE_179_MEMWAIT,
|
||
WR_EN => POKEY_WRITE_ENABLE,
|
||
RESET_N => RESET_N,
|
||
SIO_IN1 => SIO_RXD,
|
||
... | ... | |
gtia1 : entity work.gtia
|
||
PORT MAP(CLK => CLK,
|
||
WR_EN => GTIA_WRITE_ENABLE,
|
||
CPU_MEMORY_READY => MEMORY_READY_CPU,
|
||
ANTIC_MEMORY_READY => MEMORY_READY_ANTIC,
|
||
ANTIC_FETCH => ANTIC_FETCH,
|
||
CPU_ENABLE_ORIGINAL => ENABLE_179_MEMWAIT,
|
||
ANTIC_FETCH => ANTIC_FETCH, -- for first pmg fetch
|
||
CPU_ENABLE_ORIGINAL => ENABLE_179_MEMWAIT, -- for subsequent pmg fetches
|
||
RESET_N => RESET_N,
|
||
PAL => PAL,
|
||
COLOUR_CLOCK_ORIGINAL => ANTIC_ORIGINAL_COLOUR_CLOCK_OUT,
|
||
... | ... | |
AN => ANTIC_AN,
|
||
CPU_DATA_IN => WRITE_DATA(7 DOWNTO 0),
|
||
MEMORY_DATA_IN => MEMORY_DATA(7 DOWNTO 0),
|
||
VSYNC => VGA_VS,
|
||
HSYNC => VGA_HS,
|
||
BLANK => open,
|
||
VSYNC => VIDEO_VS,
|
||
HSYNC => VIDEO_HS,
|
||
BLANK => VIDEO_BLANK,
|
||
BURST => VIDEO_BURST,
|
||
START_OF_FIELD => VIDEO_START_OF_FIELD,
|
||
ODD_LINE => VIDEO_ODD_LINE,
|
||
sound => GTIA_SOUND,
|
||
COLOUR_out => COLOUR,
|
||
DATA_OUT => GTIA_DO);
|
||
... | ... | |
--Ultramarine 7, 112 Orange 15, 240
|
||
|
||
gen_palette_none : if palette=0 generate
|
||
VGA_B <= COLOUR;
|
||
VGA_R <= (others => '0');
|
||
VGA_G <= (others => '0');
|
||
VIDEO_B_WIDE <= COLOUR;
|
||
VIDEO_R_WIDE <= (others => '0');
|
||
VIDEO_G_WIDE <= (others => '0');
|
||
end generate;
|
||
|
||
gen_palette_altirra : if palette=1 generate
|
||
palette1 : entity work.gtia_palette(altirra)
|
||
port map (ATARI_COLOUR=>COLOUR, R_next=>VGA_R_WIDE, G_next=>VGA_G_WIDE, B_next=>VGA_B_WIDE);
|
||
port map (ATARI_COLOUR=>COLOUR, R_next=>VIDEO_R_WIDE, G_next=>VIDEO_G_WIDE, B_next=>VIDEO_B_WIDE);
|
||
end generate;
|
||
|
||
gen_palette_laoo : if palette=2 generate
|
||
palette2 : entity work.gtia_palette(laoo)
|
||
port map (ATARI_COLOUR=>COLOUR, R_next=>VGA_R_WIDE, G_next=>VGA_G_WIDE, B_next=>VGA_B_WIDE);
|
||
port map (ATARI_COLOUR=>COLOUR, R_next=>VIDEO_R_WIDE, G_next=>VIDEO_G_WIDE, B_next=>VIDEO_B_WIDE);
|
||
end generate;
|
||
|
||
VGA_R(video_bits-1 downto 0) <= VGA_R_WIDE(7 downto 8-video_bits);
|
||
VGA_G(video_bits-1 downto 0) <= VGA_G_WIDE(7 downto 8-video_bits);
|
||
VGA_B(video_bits-1 downto 0) <= VGA_B_WIDE(7 downto 8-video_bits);
|
||
VIDEO_R(video_bits-1 downto 0) <= VIDEO_R_WIDE(7 downto 8-video_bits);
|
||
VIDEO_G(video_bits-1 downto 0) <= VIDEO_G_WIDE(7 downto 8-video_bits);
|
||
VIDEO_B(video_bits-1 downto 0) <= VIDEO_B_WIDE(7 downto 8-video_bits);
|
||
|
||
irq_glue1 : entity work.irq_glue
|
||
PORT MAP(pokey_irq => POKEY_IRQ,
|
||
... | ... | |
-- outputs
|
||
PBI_ADDR <= PBI_ADDR_INT;
|
||
PORTB_OUT <= PORTB_OUT_INT;
|
||
ANTIC_REFRESH <= ANTIC_REFRESH_CYCLE;
|
||
|
||
END bdf_type;
|
common/a8core/atari800core_helloworld.vhd | ||
---|---|---|
|
||
video_bits : integer := 8;
|
||
|
||
internal_rom : integer :=1;
|
||
internal_ram : integer := 16384 -- at start of memory map
|
||
);
|
||
PORT
|
||
... | ... | |
RESET_N : IN STD_LOGIC;
|
||
|
||
-- VIDEO OUT - PAL/NTSC, original Atari timings approx (may be higher res)
|
||
VGA_VS : OUT STD_LOGIC;
|
||
VGA_HS : OUT STD_LOGIC;
|
||
VGA_B : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VGA_G : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VGA_R : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VIDEO_VS : OUT STD_LOGIC;
|
||
VIDEO_HS : OUT STD_LOGIC;
|
||
VIDEO_B : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VIDEO_G : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VIDEO_R : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
|
||
-- AUDIO OUT - Pokey/GTIA 1-bit and Covox all mixed
|
||
-- TODO - choose stereo/mono pokey
|
||
... | ... | |
GENERIC MAP
|
||
(
|
||
cycle_length => cycle_length,
|
||
internal_rom => 1,
|
||
internal_rom => internal_rom,
|
||
internal_ram =>internal_ram,
|
||
video_bits => video_bits
|
||
)
|
||
... | ... | |
CLK => CLK,
|
||
RESET_N => RESET_N,
|
||
|
||
VGA_VS => VGA_VS,
|
||
VGA_HS => VGA_HS,
|
||
VGA_B => VGA_B,
|
||
VGA_G => VGA_G,
|
||
VGA_R => VGA_R,
|
||
VIDEO_VS => VIDEO_VS,
|
||
VIDEO_HS => VIDEO_HS,
|
||
VIDEO_B => VIDEO_B,
|
||
VIDEO_G => VIDEO_G,
|
||
VIDEO_R => VIDEO_R,
|
||
VIDEO_BLANK => open,
|
||
VIDEO_BURST => open,
|
||
VIDEO_START_OF_FIELD => open,
|
||
VIDEO_ODD_LINE => open,
|
||
|
||
AUDIO_L => AUDIO_L,
|
||
AUDIO_R => AUDIO_R,
|
common/a8core/atari800core_simple_sdram.vhd | ||
---|---|---|
|
||
-- how many bits for video
|
||
video_bits : integer := 8;
|
||
palette : integer :=1; -- 0:gtia colour on VIDEO_B, 1:altirra, 2:laoo
|
||
|
||
-- For initial port may help to have no
|
||
internal_rom : integer := 1; -- if 0 expects it in sdram,is 1:16k os+basic, is 2:... TODO
|
||
... | ... | |
RESET_N : IN STD_LOGIC;
|
||
|
||
-- VIDEO OUT - PAL/NTSC, original Atari timings approx (may be higher res)
|
||
VGA_VS : OUT STD_LOGIC;
|
||
VGA_HS : OUT STD_LOGIC;
|
||
VGA_B : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VGA_G : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VGA_R : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VIDEO_VS : OUT STD_LOGIC;
|
||
VIDEO_HS : OUT STD_LOGIC;
|
||
VIDEO_B : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VIDEO_G : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
VIDEO_R : OUT STD_LOGIC_VECTOR(video_bits-1 DOWNTO 0);
|
||
-- These ones are probably only needed for e.g. svideo
|
||
VIDEO_BLANK : out std_logic;
|
||
VIDEO_BURST : out std_logic;
|
||
VIDEO_START_OF_FIELD : out std_logic;
|
||
VIDEO_ODD_LINE : out std_logic;
|
||
|
||
-- AUDIO OUT - Pokey/GTIA 1-bit and Covox all mixed
|
||
-- TODO - choose stereo/mono pokey
|
||
... | ... | |
SDRAM_32BIT_WRITE_ENABLE : out std_logic;
|
||
SDRAM_16BIT_WRITE_ENABLE : out std_logic;
|
||
SDRAM_8BIT_WRITE_ENABLE : out std_logic;
|
||
SDRAM_REFRESH : out std_logic;
|
||
|
||
-- DMA memory map differs
|
||
-- e.g. some special addresses to read behind hardware registers
|
||
... | ... | |
|
||
-- ANTIC
|
||
signal ANTIC_LIGHTPEN : std_logic;
|
||
signal ANTIC_REFRESH : std_logic;
|
||
signal ANTIC_REFRESH_END : std_logic;
|
||
signal SDRAM_REFRESH_NEXT : std_logic;
|
||
signal SDRAM_REFRESH_REG : std_logic;
|
||
|
||
-- CARTRIDGE ACCESS
|
||
SIGNAL CART_RD4 : STD_LOGIC;
|
||
... | ... | |
-- ANTIC lightpen
|
||
ANTIC_LIGHTPEN <= JOY2_n(4) and JOY1_n(4);
|
||
|
||
-- ANTIC REFRESH - provide hint to SDRAM of a good time to refresh
|
||
process(clk,reset_n)
|
||
begin
|
||
if (reset_n='0') then
|
||
SDRAM_REFRESH_REG <= '0';
|
||
elsif (clk'event and clk='1') then
|
||
SDRAM_REFRESH_REG <= SDRAM_REFRESH_NEXT;
|
||
end if;
|
||
end process;
|
||
|
||
process(ANTIC_REFRESH, ANTIC_REFRESH_END, SDRAM_REFRESH_REG)
|
||
begin
|
||
SDRAM_REFRESH_NEXT <= SDRAM_REFRESH_REG;
|
||
|
||
if (ANTIC_REFRESH = '1') then
|
||
SDRAM_REFRESH_NEXT <= '1';
|
||
end if;
|
||
|
||
if (ANTIC_REFRESH_END = '1') then
|
||
SDRAM_REFRESH_NEXT <= '0';
|
||
end if;
|
||
end process;
|
||
|
||
|
||
refresh_delay : entity work.delay_line
|
||
generic map (COUNT=>cycle_length)
|
||
port map(clk=>clk,sync_reset=>'0',data_in=>ANTIC_REFRESH,enable=>'1',reset_n=>reset_n,data_out=>ANTIC_REFRESH_END);
|
||
|
||
SDRAM_REFRESH <= SDRAM_REFRESH_NEXT;
|
||
|
||
-- GTIA triggers
|
||
GTIA_TRIG <= CART_RD5&"1"&JOY2_n(4)&JOY1_n(4);
|
||
|
||
... | ... | |
GENERIC MAP
|
||
(
|
||
cycle_length => cycle_length,
|
||
video_bits => video_bits
|
||
video_bits => video_bits,
|
||
palette => palette
|
||
)
|
||
PORT MAP
|
||
(
|
||
CLK => CLK,
|
||
RESET_N => RESET_N,
|
||
|
||
VGA_VS => VGA_VS,
|
||
VGA_HS => VGA_HS,
|
||
VGA_B => VGA_B,
|
||
VGA_G => VGA_G,
|
||
VGA_R => VGA_R,
|
||
VIDEO_VS => VIDEO_VS,
|
||
VIDEO_HS => VIDEO_HS,
|
||
VIDEO_B => VIDEO_B,
|
||
VIDEO_G => VIDEO_G,
|
||
VIDEO_R => VIDEO_R,
|
||
VIDEO_BLANK => VIDEO_BLANK,
|
||
VIDEO_BURST => VIDEO_BURST,
|
||
VIDEO_START_OF_FIELD => VIDEO_START_OF_FIELD,
|
||
VIDEO_ODD_LINE => VIDEO_ODD_LINE,
|
||
|
||
AUDIO_L => AUDIO_L,
|
||
AUDIO_R => AUDIO_R,
|
||
... | ... | |
GTIA_TRIG => GTIA_TRIG,
|
||
|
||
ANTIC_LIGHTPEN => ANTIC_LIGHTPEN,
|
||
ANTIC_REFRESH => ANTIC_REFRESH,
|
||
|
||
SDRAM_REQUEST => SDRAM_REQUEST,
|
||
SDRAM_REQUEST_COMPLETE => SDRAM_REQUEST_COMPLETE,
|
||
... | ... | |
SDRAM_ADDR => SDRAM_ADDR,
|
||
SDRAM_DO => SDRAM_DO,
|
||
|
||
SDRAM_REFRESH => open, -- TODO
|
||
|
||
RAM_ADDR => RAM_ADDR,
|
||
RAM_DO => RAM_DO,
|
||
RAM_REQUEST => RAM_REQUEST,
|
common/a8core/enable_divider.vhdl | ||
---|---|---|
process(clk,reset_n)
|
||
begin
|
||
if (reset_n = '0') then
|
||
count_reg <= (others=>'0');
|
||
count_reg <=std_logic_vector(to_unsigned(COUNT-1,WIDTH));
|
||
enabled_out_reg <= '0';
|
||
elsif (clk'event and clk='1') then
|
||
count_reg <= count_next;
|
common/a8core/gtia.vhdl | ||
---|---|---|
WR_EN : IN STD_LOGIC;
|
||
|
||
MEMORY_DATA_IN : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
|
||
CPU_MEMORY_READY : IN STD_LOGIC;
|
||
ANTIC_MEMORY_READY : IN STD_LOGIC;
|
||
ANTIC_FETCH : IN STD_LOGIC;
|
||
ANTIC_FETCH : in std_logic;
|
||
|
||
CPU_ENABLE_ORIGINAL : in std_logic;
|
||
CPU_ENABLE_ORIGINAL : in std_logic; -- on cycle data is ready
|
||
|
||
RESET_N : IN STD_LOGIC;
|
||
|
||
... | ... | |
VSYNC : out std_logic;
|
||
HSYNC : out std_logic;
|
||
BLANK : out std_logic;
|
||
BURST : out std_logic;
|
||
START_OF_FIELD : out std_logic;
|
||
ODD_LINE : out std_logic;
|
||
|
||
-- To speaker
|
||
sound : out std_logic
|
||
... | ... | |
|
||
signal hsync_start : std_logic;
|
||
signal hsync_end : std_logic;
|
||
|
||
signal burst_next : std_logic;
|
||
signal burst_reg : std_logic;
|
||
|
||
signal burst_start : std_logic;
|
||
signal burst_end : std_logic;
|
||
|
||
signal hblank_next : std_logic;
|
||
signal hblank_reg : std_logic;
|
||
|
||
... | ... | |
constant pmg_dma_done : std_logic_vector(2 downto 0) := "101";
|
||
constant pmg_dma_instruction : std_logic_vector(2 downto 0) := "110";
|
||
|
||
signal memory_ready : std_logic;
|
||
|
||
begin
|
||
-- register
|
||
process(clk,reset_n)
|
||
... | ... | |
|
||
vsync_reg <= '0';
|
||
hsync_reg <= '0';
|
||
burst_reg <= '0';
|
||
hblank_reg <= '0';
|
||
|
||
an_prev_reg <= (others=>'0');
|
||
... | ... | |
|
||
vsync_reg <= vsync_next;
|
||
hsync_reg <= hsync_next;
|
||
burst_reg <= burst_next;
|
||
hblank_reg <= hblank_next;
|
||
|
||
an_prev_reg <= an_prev_next;
|
||
... | ... | |
vsync_next <= vsync_reg;
|
||
|
||
odd_scanline_next <= odd_scanline_reg;
|
||
|
||
start_of_field <= '0';
|
||
|
||
-- NB high res mode gives pf2 - which is or of the two pixels
|
||
highres_next <= highres_reg;
|
||
... | ... | |
odd_scanline_next <= '0';
|
||
|
||
visible_live <= '0';
|
||
|
||
start_of_field <= not(vsync_reg);
|
||
end if;
|
||
|
||
-- during vblank we reset our own counter - since Antic does not clear hblank_reg
|
||
... | ... | |
-- end process;
|
||
|
||
-- generate hsync
|
||
process(hpos_reg, hsync_reg, hsync_end, vsync_reg, vsync_next)
|
||
process(hpos_reg, hsync_reg, hsync_end, burst_reg, burst_end, vsync_reg, vsync_next)
|
||
begin
|
||
hsync_start <= '0';
|
||
hsync_next <= hsync_reg;
|
||
|
||
burst_start <= '0';
|
||
burst_next <= burst_reg;
|
||
|
||
if (unsigned(hpos_reg) = X"D4" and vsync_reg = '1') then
|
||
hsync_start <= '1';
|
||
... | ... | |
hsync_start <= '1';
|
||
hsync_next <= '1';
|
||
end if;
|
||
|
||
if (unsigned(hpos_reg) = X"14" and vsync_reg = '0' ) then
|
||
burst_start <= '1';
|
||
burst_next <= '1';
|
||
end if;
|
||
|
||
if (hsync_end = '1') then
|
||
hsync_next <= '0';
|
||
end if;
|
||
|
||
if (burst_end = '1') then
|
||
burst_next <= '0';
|
||
end if;
|
||
|
||
if (vsync_next = '0' and vsync_reg = '1') then
|
||
hsync_next <= '0';
|
||
... | ... | |
generic map (COUNT=>15)
|
||
port map(clk=>clk,sync_reset=>'0',data_in=>hsync_start,enable=>COLOUR_CLOCK_ORIGINAL,reset_n=>reset_n,data_out=>hsync_end);
|
||
|
||
burst_delay : delay_line
|
||
generic map (COUNT=>8)
|
||
port map(clk=>clk,sync_reset=>'0',data_in=>burst_start,enable=>COLOUR_CLOCK_ORIGINAL,reset_n=>reset_n,data_out=>burst_end);
|
||
|
||
-- pmg dma
|
||
MEMORY_READY <= CPU_MEMORY_READY or ANTIC_MEMORY_READY; -- TODO, REVIEW timing vs CPU/ANTIC - simpler may be possible now
|
||
process(antic_fetch,CPU_ENABLE_ORIGINAL,memory_ready,memory_data_in,hsync_start,pmg_dma_state_reg,gractl_reg,odd_scanline_reg,vdelay_reg,grafm_reg, visible_live,hpos_reg, hblank_reg)
|
||
process(CPU_ENABLE_ORIGINAL,antic_fetch,memory_data_in,hsync_start,pmg_dma_state_reg,gractl_reg,odd_scanline_reg,vdelay_reg,grafm_reg, visible_live,hpos_reg, hblank_reg)
|
||
begin
|
||
pmg_dma_state_next <= pmg_dma_state_reg;
|
||
grafm_dma_load <= '0';
|
||
... | ... | |
pmg_dma_state_next <= pmg_dma_missile;
|
||
end if;
|
||
|
||
-- we start from the first antic refresh cycle
|
||
-- we start from the first antic fetch
|
||
-- TODO - CPU enable does not identify next 'antic' cycle in turbo mode...
|
||
case pmg_dma_state_reg is
|
||
when pmg_dma_missile =>
|
||
if (antic_fetch = '1' and memory_ready = '1' and hblank_reg = '1' and visible_live = '0' and hpos_reg(7 downto 4) = "0000") then
|
||
if (antic_fetch = '1' and cpu_enable_original = '1' and hblank_reg = '1' and visible_live = '0' and hpos_reg(7 downto 4) = "0000") then
|
||
-- here we have the missile0
|
||
grafm_dma_load <= gractl_reg(0);
|
||
|
||
... | ... | |
pmg_dma_state_next <= pmg_dma_instruction;
|
||
end if;
|
||
when pmg_dma_instruction =>
|
||
if (((CPU_ENABLE_ORIGINAL or antic_fetch) and memory_ready) = '1') then
|
||
if (CPU_ENABLE_ORIGINAL = '1') then
|
||
pmg_dma_state_next <= pmg_dma_player0;
|
||
end if;
|
||
when pmg_dma_player0 =>
|
||
if (((CPU_ENABLE_ORIGINAL or antic_fetch) and memory_ready) = '1') then
|
||
if (CPU_ENABLE_ORIGINAL = '1') then
|
||
-- here we have player0
|
||
grafp0_dma_next <= memory_data_in;
|
||
grafp0_dma_load <= gractl_reg(1) and (odd_scanline_reg or not(vdelay_reg(4)));
|
||
pmg_dma_state_next <= pmg_dma_player1;
|
||
end if;
|
||
when pmg_dma_player1 =>
|
||
if (((CPU_ENABLE_ORIGINAL or antic_fetch) and memory_ready) = '1') then
|
||
if (CPU_ENABLE_ORIGINAL = '1') then
|
||
-- here we have player1
|
||
grafp1_dma_next <= memory_data_in;
|
||
grafp1_dma_load <= gractl_reg(1) and (odd_scanline_reg or not(vdelay_reg(5)));
|
||
pmg_dma_state_next <= pmg_dma_player2;
|
||
end if;
|
||
when pmg_dma_player2 =>
|
||
if (((CPU_ENABLE_ORIGINAL or antic_fetch) and memory_ready) = '1') then
|
||
if (CPU_ENABLE_ORIGINAL = '1') then
|
||
-- here we have player1
|
||
grafp2_dma_next <= memory_data_in;
|
||
grafp2_dma_load <= gractl_reg(1) and (odd_scanline_reg or not(vdelay_reg(6)));
|
||
pmg_dma_state_next <= pmg_dma_player3;
|
||
end if;
|
||
when pmg_dma_player3 =>
|
||
if (((CPU_ENABLE_ORIGINAL or antic_fetch) and memory_ready) = '1') then
|
||
if (CPU_ENABLE_ORIGINAL = '1') then
|
||
-- here we have player1
|
||
grafp3_dma_next <= memory_data_in;
|
||
grafp3_dma_load <= gractl_reg(1) and (odd_scanline_reg or not(vdelay_reg(7)));
|
||
... | ... | |
vsync<=vsync_reg;
|
||
hsync<=hsync_reg;
|
||
blank<=hblank_reg or vsync_reg;
|
||
burst<=burst_reg;
|
||
odd_line<=odd_scanline_reg;
|
||
|
||
sound <= consol_output_reg(3);
|
||
|
common/a8core/pokey.vhdl | ||
---|---|---|
PORT
|
||
(
|
||
CLK : IN STD_LOGIC;
|
||
--ENABLE_179 :in std_logic;
|
||
CPU_MEMORY_READY :in std_logic;
|
||
ANTIC_MEMORY_READY :in std_logic;
|
||
ENABLE_179 :in std_logic;
|
||
ADDR : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
|
||
DATA_IN : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
|
||
WR_EN : IN STD_LOGIC;
|
||
... | ... | |
|
||
signal pot_reset_next : std_logic;
|
||
signal pot_reset_reg : std_logic;
|
||
|
||
signal enable_179 : std_logic;
|
||
BEGIN
|
||
--HACK FIXME TODO
|
||
enable_179 <= cpu_MEMORY_READY or antIC_MEMORY_READY;
|
||
|
||
-- register
|
||
process(clk,reset_n)
|
||
begin
|
common/a8core/shared_enable.vhdl | ||
---|---|---|
LIBRARY ieee;
|
||
USE ieee.std_logic_1164.all;
|
||
use ieee.numeric_std.all;
|
||
USE ieee.math_real.ceil;
|
||
USE ieee.math_real.log2;
|
||
|
||
-- TODO - review this whole scheme
|
||
-- Massively overcomplex and turbo doesn't even work with it right now!
|
||
... | ... | |
(
|
||
CLK : IN STD_LOGIC;
|
||
RESET_N : IN STD_LOGIC;
|
||
ANTIC_REFRESH : IN STD_LOGIC;
|
||
MEMORY_READY_CPU : IN STD_LOGIC; -- during memory wait states keep CPU awake
|
||
MEMORY_READY_ANTIC : IN STD_LOGIC; -- during memory wait states keep CPU awake
|
||
PAUSE_6502 : in std_logic;
|
||
THROTTLE_COUNT_6502 : in std_logic_vector(5 downto 0);
|
||
|
||
ANTIC_ENABLE_179 : OUT STD_LOGIC; -- always about 1.79MHz to keep sound the same - 1 cycle early
|
||
oldcpu_enable : OUT STD_LOGIC; -- always about 1.79MHz to keep sound the same - expanded to next ready
|
||
oldcpu_enable : OUT STD_LOGIC; -- always about 1.79MHz to keep sound the same - 1 cycle only, when memory is ready...
|
||
CPU_ENABLE_OUT : OUT STD_LOGIC -- for compatibility run at 1.79MHz, for speed run as fast as we can
|
||
|
||
-- antic DMA runs 1 cycle after 'enable', so ANTIC_ENABLE is delayed by 31 cycles vs CPU_ENABLE (when in 1.79MHz mode)
|
||
-- XXX watch out on clock speed change from 56MHz!
|
||
-- antic DMA runs 1 cycle after 'enable', so ANTIC_ENABLE is delayed by cycle_length-1 cycles vs CPU_ENABLE (when in 1.79MHz mode)
|
||
);
|
||
END shared_enable;
|
||
|
||
... | ... | |
signal cpu_extra_enable_next : std_logic;
|
||
signal cpu_extra_enable_reg : std_logic;
|
||
|
||
signal turbo_next : std_logic;
|
||
signal turbo_reg : std_logic;
|
||
|
||
signal throttle_count_next : std_logic_vector(5 downto 0);
|
||
signal throttle_count_reg : std_logic_vector(5 downto 0);
|
||
signal speed_shift_next : std_logic_vector(cycle_length-1 downto 0);
|
||
signal speed_shift_reg : std_logic_vector(cycle_length-1 downto 0);
|
||
|
||
-- TODO - clean up
|
||
signal oldcpu_extra_enable_next : std_logic;
|
||
signal oldcpu_extra_enable_reg : std_logic;
|
||
signal enable_179_expanded : std_logic;
|
||
signal oldcpu_pending_next : std_logic;
|
||
signal oldcpu_pending_reg : std_logic;
|
||
signal oldcpu_go : std_logic;
|
||
|
||
signal memory_ready : std_logic;
|
||
|
||
constant cycle_length_bits: integer := integer(ceil(log2(real(cycle_length))));
|
||
begin
|
||
-- instantiate some clock calcs
|
||
enable_179_clock_div : enable_divider
|
||
generic map (COUNT=>cycle_length)
|
||
port map(clk=>clk,reset_n=>reset_n,enable_in=>'1',enable_out=>enable_179);
|
||
|
||
process(THROTTLE_COUNT_6502, throttle_count_reg, enable_179)
|
||
process(THROTTLE_COUNT_6502, speed_shift_reg, enable_179)
|
||
variable speed_shift : std_logic;
|
||
variable speed_shift_temp : std_logic_vector(cycle_length-1 downto 0);
|
||
begin
|
||
turbo_next <= '0';
|
||
throttle_count_next <= std_logic_vector(unsigned(throttle_count_reg) + 1);
|
||
|
||
--011111/31/1f = run every 32 cycles
|
||
|
||
if (throttle_count_reg = THROTTLE_COUNT_6502) then
|
||
throttle_count_next <= (others=>'0');
|
||
turbo_next <= '1';
|
||
end if;
|
||
|
||
if (enable_179 = '1') then -- synchronize
|
||
throttle_count_next <= "000001";
|
||
speed_shift_temp(cycle_length-1 downto 1) := (others=>'0');
|
||
speed_shift_temp(0) := '1';
|
||
else
|
||
speed_shift_temp := speed_shift_reg;
|
||
end if;
|
||
--0000000000111111111122222222223333
|
||
--0123456789012345678901234567890123
|
||
--X-------------------------------X
|
||
--
|
||
--000000000011111111112222222222333
|
||
--R12345678901234567890123456789012
|
||
---------------------------------NT
|
||
|
||
speed_shift_next(cycle_length-1 downto 1) <= speed_shift_temp(cycle_length-2 downto 0);
|
||
|
||
--000000000011111100000000001111111
|
||
--R12345678901234501234567890123456
|
||
-----------------NT--------------NT
|
||
speed_shift := '0';
|
||
|
||
for i in 0 to cycle_length_bits loop
|
||
speed_shift := speed_shift or (speed_shift_temp(cycle_length/(2**i)-1) and throttle_count_6502(i));
|
||
end loop;
|
||
|
||
speed_shift_next(0) <= speed_shift;
|
||
end process;
|
||
|
||
delay_line_phase : delay_line
|
||
... | ... | |
begin
|
||
if (reset_n = '0') then
|
||
cpu_extra_enable_reg <= '0';
|
||
oldcpu_extra_enable_reg <= '0';
|
||
turbo_reg <= '0';
|
||
throttle_count_reg <= (others=>'0');
|
||
oldcpu_pending_reg <= '0';
|
||
speed_shift_reg <= (others=>'0');
|
||
elsif (clk'event and clk='1') then
|
||
cpu_extra_enable_reg <= cpu_extra_enable_next;
|
||
oldcpu_extra_enable_reg <= oldcpu_extra_enable_next;
|
||
turbo_reg <= turbo_next;
|
||
throttle_count_reg <= throttle_count_next;
|
||
oldcpu_pending_reg <= oldcpu_pending_next;
|
||
speed_shift_reg <= speed_shift_next;
|
||
end if;
|
||
end process;
|
||
|
||
-- next state
|
||
memory_ready <= memORY_READY_CPU or memORY_READY_ANTIC;
|
||
cpu_enable <= (turbo_reg or cpu_extra_enable_reg or enable_179) and not(pause_6502);
|
||
cpu_enable <= (speed_shift_reg(0) or cpu_extra_enable_reg or enable_179) and not(pause_6502 or antic_refresh);
|
||
cpu_extra_enable_next <= cpu_enable and not(memory_ready);
|
||
|
||
oldcpu_extra_enable_next <= enable_179_expanded and not(memory_ready);
|
||
enable_179_expanded <= oldcpu_extra_enable_reg or enable_179;
|
||
oldcpu_pending_next <= (oldcpu_pending_reg or enable_179) and not(memory_ready or antic_refresh);
|
||
oldcpu_go <= (oldcpu_pending_reg or enable_179) and (memory_ready or antic_refresh);
|
||
|
||
-- output
|
||
oldcpu_enable <= enable_179_expanded;
|
||
oldcpu_enable <= oldcpu_go;
|
||
ANTIC_ENABLE_179 <= enable_179_early;
|
||
|
||
CPU_ENABLE_OUT <= cpu_enable; -- run at 25MHz
|
Also available in: Unified diff
No need for mmu to deal with refresh at all