mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-02-02 14:50:52 +00:00
526 lines
19 KiB
VHDL
526 lines
19 KiB
VHDL
--
|
|
-- A simulation model of ULA
|
|
-- Copyright (c) seilebost - 2001 - 2009
|
|
--
|
|
-- 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 seilebost@free.fr
|
|
--
|
|
--
|
|
--
|
|
--
|
|
-- 2013 Significant rewrite by d18c7db(a)hotmail
|
|
--
|
|
-- Combined all ULA submodules into one file
|
|
-- Elliminated gated clocks
|
|
-- Overall simplified and streamlined RTL
|
|
-- Reduced number of synthesis warnings
|
|
-- Fixed attribute decoding
|
|
-- Fixed phase1/phase2 address generation
|
|
-- Changes in timing signal generation
|
|
-- Fixed attributes not alligned to characters on screen
|
|
-- Implemented 50/60Hz attribute
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.std_logic_unsigned.all;
|
|
|
|
-- ULA pinout
|
|
-- 1 MUX U RAM_D1 40
|
|
-- 2 RAM_D2 RAM_D0 39
|
|
-- 3 RAM_D3 RAM_D7 38
|
|
-- 4 RAM_D4 RAM_D5 37
|
|
-- 5 D5 RAM_D6 36
|
|
-- 6 GND A12 35
|
|
-- 7 CLK D6 34
|
|
-- 8 D0 A09 33
|
|
-- 9 CAS A08 32
|
|
-- 10 RAS A10 31
|
|
-- 11 D2 A15 30
|
|
-- 12 D3 A14 29
|
|
-- 13 D4 RAM_R/W 28
|
|
-- 14 PHI R/W 27
|
|
-- 15 A11 MAP 26
|
|
-- 16 SYNC I/O 25
|
|
-- 17 D1 Vcc 24
|
|
-- 18 D7 ROM_CS 23
|
|
-- 19 BLU A13 22
|
|
-- 20 GRN RED 21
|
|
|
|
entity ula is
|
|
port (
|
|
RESETn : in std_logic; -- RESET master
|
|
CLK_4 : out std_logic; -- 4 MHz internal
|
|
|
|
CLK : in std_logic; -- 24 MHz -- pin 07
|
|
PHI2 : out std_logic; -- 1 MHz CPU & system -- pin 14
|
|
RW : in std_logic; -- R/W from CPU -- pin 27
|
|
MAPn : in std_logic; -- MAP -- pin 26
|
|
DB : in std_logic_vector( 7 downto 0); -- DATA BUS -- pin 18,34,5,13,12,11,17,8
|
|
ADDR : in std_logic_vector(15 downto 0); -- ADDRESS BUS -- pin 30,29,22,35,15,31,33,32, A7,A6,A5,A4,A3,A2,A1,A0
|
|
|
|
-- SRAM
|
|
CSRAMn : out std_logic;
|
|
SRAM_AD : out std_logic_vector(15 downto 0);
|
|
SRAM_OE : out std_logic;
|
|
SRAM_CE : out std_logic;
|
|
SRAM_WE : out std_logic;
|
|
LATCH_SRAM : out std_logic;
|
|
|
|
-- DRAM
|
|
-- AD_RAM : out std_logic_vector( 7 downto 0); -- ADDRESS BUS for dynamic ram -- pin 38,36,37,4,3,2,40,39
|
|
-- RASn : out std_logic; -- RAS for dynamic ram -- pin 10
|
|
-- CASn : out std_logic; -- CAS for dynamic ram -- pin 09
|
|
-- MUX : out std_logic; -- MUX selector -- pin 01
|
|
-- RW_RAM : out std_logic; -- Read/Write for dynamic ram -- pin 28
|
|
|
|
CSIOn : out std_logic; -- Chip select IO (VIA) -- pin 25
|
|
CSROMn : out std_logic; -- ROM select -- pin 23
|
|
R : out std_logic; -- Red -- pin 21
|
|
G : out std_logic; -- Green -- pin 20
|
|
B : out std_logic; -- Blue -- pin 19
|
|
SYNC : out std_logic; -- Synchronisation -- pin 16
|
|
-- VCC -- pin 24
|
|
-- GND -- pin 06
|
|
HSYNC : out std_logic;
|
|
VSYNC : out std_logic
|
|
);
|
|
end;
|
|
|
|
architecture RTL of ula is
|
|
|
|
-- Signal CLOCK
|
|
signal CLK_24 : std_logic; -- CLOCK 24 MHz internal
|
|
signal CLK_4_INT : std_logic; -- CLOCK 4 MHz internal
|
|
signal CLK_1_INT : std_logic; -- CLOCK 1 MHz internal
|
|
signal CLK_PIXEL_INT : std_logic; -- CLOCK PIXEL internal
|
|
signal CLK_FLASH : std_logic; -- CLOCK FLASH external
|
|
|
|
-- Data Bus Internal
|
|
signal DB_INT : std_logic_vector( 7 downto 0);
|
|
|
|
-- Manage memory access
|
|
signal VAP1 : std_logic_vector(15 downto 0); -- VIDEO ADDRESS PHASE 1
|
|
signal VAP2 : std_logic_vector(15 downto 0); -- VIDEO ADDRESS PHASE 2
|
|
signal lADDR : std_logic_vector(15 downto 0); -- BUS ADDRESS PROCESSOR
|
|
signal RW_INT : std_logic; -- Read/Write INTERNAL FROM CPU
|
|
|
|
-- local signal
|
|
signal lHIRES_SEL : std_logic; -- TXT/HIRES SELECT
|
|
signal HIRES_DEC : std_logic; -- TXT/HIRES DECODE
|
|
signal lDBLHGT_SEL : std_logic; -- Double Height SELECT
|
|
signal lALT_SEL : std_logic; -- Character set select
|
|
signal lFORCETXT : std_logic; -- Force text mode
|
|
signal isAttrib : std_logic; -- Attrib
|
|
signal ATTRIB_DEC : std_logic; -- Attrib decode
|
|
-- signal LD_REG_0 : std_logic; -- Load zero into video register
|
|
signal RELD_REG : std_logic; -- Reload from register to shift
|
|
signal DATABUS_EN : std_logic; -- Data bus enable
|
|
signal lCOMPSYNC : std_logic; -- Composite Synchronization for video
|
|
signal lHSYNCn : std_logic; -- Horizontal Synchronization for video
|
|
signal lVSYNC50n : std_logic; -- Vertical Synchronization for 50Hz video
|
|
signal lVSYNC60n : std_logic; -- Vertical Synchronization for 60Hz video
|
|
signal lVSYNCn : std_logic; -- Vertical Synchronization for video
|
|
signal BLANKINGn : std_logic; -- Blanking signal
|
|
signal lRELOAD_SEL : std_logic; -- reload register SELECT
|
|
signal lFREQ_SEL : std_logic; -- Frequency video SELECT (50 or 60 Hz)
|
|
signal LDFROMBUS : std_logic; -- Load from Bus Data
|
|
signal CHROWCNT : std_logic_vector( 2 downto 0); -- ch?? row count
|
|
signal lCTR_H : std_logic_vector( 6 downto 0); -- Horizontal counter
|
|
signal lCTR_V : std_logic_vector( 8 downto 0); -- Vertical counter
|
|
|
|
signal rgb_int : std_logic_vector( 2 downto 0); -- Red Green Blue video signal
|
|
|
|
-- local select RAM, IO & ROM
|
|
signal CSRAMn_INT : std_logic; -- RAM Chip Select
|
|
signal CSIOn_INT : std_logic; -- Input/Output Chip Select
|
|
signal CSROMn_INT : std_logic; -- ROM Chip select
|
|
|
|
-- Bus Address internal
|
|
signal AD_RAM_INT : std_logic_vector(15 downto 0); -- RAM ADDRESS BUS
|
|
|
|
-- RESET internal
|
|
signal RESET_INT : std_logic;
|
|
|
|
-- MAP internal
|
|
signal lMAPn : std_logic;
|
|
|
|
signal DBLHGT_EN : std_logic; -- ENABLE DOUBLE HEIGHT
|
|
signal CTR_V_DIV8 : std_logic_vector( 8 downto 0); -- VERTICAL COUNTER DIVIDE OR NOT BY 8
|
|
signal voffset : std_logic_vector(15 downto 0); -- OFFSET SCREEN
|
|
signal mulBy40 : std_logic_vector(14 downto 0); -- Used to mult by 40
|
|
|
|
signal c : std_logic_vector(23 downto 0); -- states
|
|
signal ph : std_logic_vector( 2 downto 0); -- phases
|
|
|
|
signal lCTR_FLASH : std_logic_vector( 4 downto 0);
|
|
signal lVBLANKn : std_logic;
|
|
signal lHBLANKn : std_logic;
|
|
|
|
signal lDATABUS : std_logic_vector( 7 downto 0);
|
|
signal lSHFREG : std_logic_vector( 5 downto 0);
|
|
signal lREGHOLD : std_logic_vector( 6 downto 0);
|
|
signal lRGB : std_logic_vector( 2 downto 0);
|
|
signal lREG_INK : std_logic_vector( 2 downto 0);
|
|
signal lREG_STYLE : std_logic_vector( 2 downto 0);
|
|
signal lREG_PAPER : std_logic_vector( 2 downto 0);
|
|
signal lREG_MODE : std_logic_vector( 2 downto 0);
|
|
signal ModeStyle : std_logic_vector( 1 downto 0);
|
|
signal lADD : std_logic_vector( 5 downto 0);
|
|
signal lInv : std_logic; -- inverse signal
|
|
signal lInv_hold : std_logic; -- inverse signal hold
|
|
signal lBGFG_SEL : std_logic;
|
|
signal lFLASH_SEL : std_logic;
|
|
|
|
begin
|
|
|
|
-- input assignments
|
|
lADDR <= ADDR;
|
|
DB_INT <= DB;
|
|
CLK_24 <= CLK;
|
|
RESET_INT <= not RESETn;
|
|
lMAPn <= MAPn;
|
|
RW_INT <= RW;
|
|
|
|
-- output assignments
|
|
PHI2 <= CLK_1_INT;
|
|
-- AD_RAM <= AD_RAM_INT(15 downto 8);
|
|
CSIOn <= CSIOn_INT;
|
|
CSROMn <= CSROMn_INT;
|
|
CSRAMn <= CSRAMn_INT;
|
|
CLK_4 <= CLK_4_INT;
|
|
|
|
------------------
|
|
-- SRAM signals --
|
|
------------------
|
|
SRAM_AD <= AD_RAM_INT;
|
|
LATCH_SRAM <= not c(4) and not c(12) and not c(20);
|
|
|
|
-- phase 1 phase 2 phase 3
|
|
SRAM_OE <= ph(0) or ph(1) or RW_INT ;
|
|
SRAM_CE <= ph(0) or ph(1) or (ph(2) and (not CSRAMn_INT) );
|
|
|
|
SRAM_WE <= (not CSRAMn_INT) and (not RW_INT) and c(17) ;
|
|
|
|
-- VIDEO OUT
|
|
R <= RGB_INT(0);
|
|
G <= RGB_INT(1);
|
|
B <= RGB_INT(2);
|
|
SYNC <= lCOMPSYNC;
|
|
HSYNC <= lHSYNCn;
|
|
VSYNC <= lVSYNCn;
|
|
|
|
----------------------
|
|
----------------------
|
|
-- Address Decoding --
|
|
----------------------
|
|
----------------------
|
|
|
|
-- PAGE 3 I/O decoder : 0x300-0x3FF
|
|
CSIOn_INT <= '0' when (lADDR(15 downto 8) = x"03") and (CLK_1_INT = '1') else '1';
|
|
|
|
-- PAGE ROM : 0xC000-0xFFFF
|
|
CSROMn_INT <= '0' when (lADDR(15 downto 14) = "11" and lMAPn = '1' and CLK_1_INT = '1') else '1';
|
|
|
|
CSRAMn_INT <= '0' when -- shadow RAM section
|
|
(lADDR(15 downto 14) = "11" and lMAPn = '0' and CLK_1_INT = '1')
|
|
or
|
|
-- normal RAM section
|
|
(((lADDR(15 downto 8) /= x"03") and (lADDR(15 downto 14) /= "11")) and lMAPn = '1' and CLK_1_INT = '1')
|
|
else '1';
|
|
|
|
----------------------------------------------
|
|
----------------------------------------------
|
|
-- Control signal generation and sequencing --
|
|
----------------------------------------------
|
|
----------------------------------------------
|
|
|
|
-- state and phase shifter
|
|
U_TB_CPT: process (CLK_24, RESET_INT)
|
|
begin
|
|
if (RESET_INT = '1') then
|
|
c <= "000000000000000000000001";
|
|
ph <= "001";
|
|
elsif falling_edge(CLK_24) then
|
|
-- advance states
|
|
c <= c(22 downto 0) & c(23);
|
|
if (c(7) or c(15) or c(23)) = '1' then
|
|
-- advance phases
|
|
ph <= ph(1 downto 0) & ph(2);
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
----------------------
|
|
-- Clock generation --
|
|
----------------------
|
|
|
|
-- CPU clock --
|
|
CLK_1_INT <= ph(2);
|
|
|
|
-- VIA 6522 clock
|
|
CLK_4_INT <= c(0) or c(1) or c(2) or c(6) or c(7) or c(8) or c(12) or c(13) or c(14) or c(18) or c(19) or c(20);
|
|
|
|
-- LD_REG_0 <= isAttrib and c(5);
|
|
|
|
CLK_PIXEL_INT <= c(1) or c(5) or c(9) or c(13) or c(17) or c(21);
|
|
ATTRIB_DEC <= c(3);
|
|
RELD_REG <= c(17);
|
|
DATABUS_EN <= c(2) or c(10);
|
|
LDFROMBUS <= ((not isAttrib) and c(12) and (not HIRES_DEC)) or ((not isAttrib) and c(5) and HIRES_DEC) or (isAttrib and c(9));
|
|
|
|
-------------------------------------
|
|
-------------------------------------
|
|
-- Video timing signals generation --
|
|
-------------------------------------
|
|
-------------------------------------
|
|
|
|
-- Horizontal Counter
|
|
u_CPT_H: process(CLK_1_INT, RESET_INT)
|
|
begin
|
|
if (RESET_INT = '1') then
|
|
lCTR_H <= (others => '0');
|
|
elsif rising_edge(CLK_1_INT) then
|
|
if lCTR_H < 63 then
|
|
lCTR_H <= lCTR_H + 1;
|
|
else
|
|
lCTR_H <= (others => '0');
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- Vertical Counter
|
|
u_CPT_V: process(CLK_1_INT, RESET_INT)
|
|
begin
|
|
if (RESET_INT = '1') then
|
|
lCTR_V <= (others => '0');
|
|
lCTR_FLASH <= (others => '0');
|
|
elsif rising_edge(CLK_1_INT) then
|
|
if (lCTR_H = 63) then
|
|
-- 50Hz = 312 lines, 60Hz = 260 lines
|
|
if ((lCTR_V < 312) and lFREQ_SEL='1') or
|
|
((lCTR_V < 260) and lFREQ_SEL='0') then
|
|
lCTR_V <= lCTR_V + 1;
|
|
else
|
|
lCTR_V <= (others => '0');
|
|
-- increment flash counter every frame
|
|
lCTR_FLASH <= lCTR_FLASH + 1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
|
|
|
|
-- Horizontal Synchronisation
|
|
lHSYNCn <= '0' when (lCTR_H >= 49) and (lCTR_H <= 53) else '1';
|
|
|
|
-- Horizontal Blank
|
|
lHBLANKn <= '1' when (lCTR_H >= 1) and (lCTR_H <= 40) else '0';
|
|
|
|
-- Signal to Reload Register to reset attributes
|
|
lRELOAD_SEL <= '1' when (lCTR_H >= 49) else '0';
|
|
|
|
-- Vertical Synchronisation
|
|
lVSYNC50n <= '0' when (lCTR_V >= 258) and (lCTR_V <= 259) else '1'; -- 50Hz
|
|
lVSYNC60n <= '0' when (lCTR_V >= 241) and (lCTR_V <= 242) else '1'; -- 60Hz
|
|
lVSYNCn <= lVSYNC50n when lFREQ_SEL='1' else lVSYNC60n;
|
|
|
|
-- Vertical Blank
|
|
lVBLANKn <= '0' when (lCTR_V >= 224) else '1';
|
|
|
|
-- Signal To Force TEXT MODE
|
|
lFORCETXT <= '1' when (lCTR_V > 199) else '0';
|
|
|
|
-- Assign output signals
|
|
CLK_FLASH <= lCTR_FLASH(4); -- Flash clock toggles every 16 video frames
|
|
lCOMPSYNC <= not (lHSYNCn xor lVSYNCn);
|
|
BLANKINGn <= lVBLANKn and lHBLANKn;
|
|
|
|
|
|
|
|
-----------------------------
|
|
-----------------------------
|
|
-- Video attribute decoder --
|
|
-----------------------------
|
|
-----------------------------
|
|
|
|
-- Latch data from Data Bus
|
|
u_data_bus: process
|
|
begin
|
|
wait until rising_edge(CLK_24);
|
|
if (DATABUS_EN = '1') then
|
|
lDATABUS <= DB_INT;
|
|
end if;
|
|
end process;
|
|
|
|
u_isattrib : process(CLK_24, RESET_INT)
|
|
begin
|
|
if (RESET_INT = '1') then
|
|
IsATTRIB <= '0';
|
|
lInv_hold <= '0';
|
|
elsif rising_edge(CLK_24) then
|
|
if ATTRIB_DEC = '1' then
|
|
IsATTRIB <= not (DB_INT(6) or DB_INT(5)); -- 1 = attribute, 0 = not an attribute
|
|
lInv_hold <= DB_INT(7);
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
u_lInv_hold : process
|
|
begin
|
|
wait until rising_edge(CLK_24);
|
|
if (CLK_PIXEL_INT = '1' and RELD_REG = '1') then
|
|
lInv <= lInv_hold;
|
|
end if;
|
|
end process;
|
|
|
|
-- hold data bus value
|
|
u_hold_reg: process(CLK_24, RESET_INT)
|
|
begin
|
|
if (RESET_INT = '1') then
|
|
lREGHOLD <= (others => '0');
|
|
elsif rising_edge(CLK_24) then
|
|
if LDFROMBUS = '1' then
|
|
lREGHOLD <= lDATABUS(6 downto 0);
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
u_ld_reg: process(CLK_24, lRELOAD_SEL, RESET_INT)
|
|
begin
|
|
if (RESET_INT = '1') then
|
|
lREG_INK <= (others=>'1');
|
|
lREG_STYLE <= (others=>'0');
|
|
lREG_PAPER <= (others=>'0');
|
|
lREG_MODE <= (others=>'0');
|
|
elsif (lRELOAD_SEL = '1') then
|
|
lREG_INK <= (others=>'1');
|
|
lREG_STYLE <= (others=>'0');
|
|
lREG_PAPER <= (others=>'0');
|
|
elsif rising_edge(CLK_24) then
|
|
if (RELD_REG = '1' and isAttrib = '1') then
|
|
case lREGHOLD(6 downto 3) is
|
|
when "0000" => lREG_INK <= lREGHOLD(2 downto 0);
|
|
when "0001" => lREG_STYLE <= lREGHOLD(2 downto 0);
|
|
when "0010" => lREG_PAPER <= lREGHOLD(2 downto 0);
|
|
when "0011" => lREG_MODE <= lREGHOLD(2 downto 0);
|
|
when others => null;
|
|
end case;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- selector bits in mode/style registers
|
|
lALT_SEL <= lREG_STYLE(0); -- Character set select : 0=Standard 1=Alternate
|
|
lDBLHGT_SEL <= lREG_STYLE(1); -- Character type select: 0=Standard 1=Double
|
|
lFLASH_SEL <= lREG_STYLE(2); -- Flash select : 0=Steady 1=Flashing
|
|
lFREQ_SEL <= lREG_MODE(1); -- Frequency select : 0=60Hz 1=50Hz
|
|
lHIRES_SEL <= lREG_MODE(2); -- Mode Select : 0=Text 1=Hires
|
|
|
|
-- Output signal for text/hires mode decode
|
|
HIRES_DEC <= (lHIRES_SEL and (not lFORCETXT));
|
|
DBLHGT_EN <= (lDBLHGT_SEL and (not HIRES_DEC));
|
|
|
|
-- shift video data
|
|
u_shf_reg: process
|
|
begin
|
|
wait until rising_edge(CLK_24);
|
|
if CLK_PIXEL_INT = '1' then
|
|
-- Load shifter before the rising edge of PHI2
|
|
if (RELD_REG = '1' and isAttrib = '0') then
|
|
lSHFREG <= lREGHOLD(5 downto 0);
|
|
else
|
|
-- send 6 bits
|
|
lSHFREG <= lSHFREG(4 downto 0) & '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
lBGFG_SEL <= '0' when ( (CLK_FLASH = '1') and (lFLASH_SEL = '1') ) else lSHFREG(5);
|
|
|
|
-- local assign for R(ed)G(reen)B(lue) signal
|
|
lRGB <= lREG_INK when lBGFG_SEL = '1' else lREG_PAPER;
|
|
|
|
-- Assign out signal
|
|
RGB_INT <= lRGB when (lInv = '0' and BLANKINGn = '1') else
|
|
not(lRGB) when (lInv = '1' and BLANKINGn = '1') else
|
|
(others=>'0');
|
|
|
|
-- Compute offset
|
|
ModeStyle <= lHIRES_SEL & lALT_SEL;
|
|
with ModeStyle select
|
|
lADD <= "100111" when "11", -- HIRES & ALT x9Cxx
|
|
"100110" when "10", -- HIRES & STD x98xx
|
|
"101110" when "01", -- TEXT & ALT xB8xx
|
|
"101101" when others; -- TEXT & STD xB4xx
|
|
|
|
-----------------------------
|
|
-----------------------------
|
|
-- Video address generator --
|
|
-----------------------------
|
|
-----------------------------
|
|
|
|
-- divide by 8 in LORES
|
|
CTR_V_DIV8 <= lCTR_V when (HIRES_DEC = '1') else "000" & lCTR_V(8 downto 3) ;
|
|
|
|
-- to multiply by 40 without using a multiplier we just sum the results of the operations of
|
|
-- multiply by 32 by shifting 5 bits and multiply by 8 by shifting 3 bits
|
|
mulBy40 <= ("0" & CTR_V_DIV8 & "00000") + ("000" & CTR_V_DIV8 & "000");
|
|
voffset <= X"A000" when (HIRES_DEC = '1') else X"BB80";
|
|
|
|
-- Generate Address Phase 1
|
|
VAP1 <= (voffset + mulBy40) + lCTR_H;
|
|
|
|
-- Compute character row counter
|
|
CHROWCNT <= lCTR_V(3 downto 1) when (DBLHGT_EN = '1') else lCTR_V(2 downto 0);
|
|
-- Generate Address Phase 2
|
|
VAP2 <= lADD & lDATABUS(6 downto 0) & CHROWCNT;
|
|
|
|
-- multiplex addresses at rising edge of each phase
|
|
addr_latch: process
|
|
begin
|
|
wait until rising_edge(CLK_24);
|
|
if c(0) = '1' then
|
|
-- Generate video phase 1 address
|
|
AD_RAM_INT <= VAP1;
|
|
elsif c(8) = '1' then
|
|
-- Generate video phase 2 address
|
|
AD_RAM_INT <= VAP2;
|
|
elsif c(16) = '1' then
|
|
-- Generate CPU phase 3 address
|
|
AD_RAM_INT <= lADDR;
|
|
end if;
|
|
end process;
|
|
end architecture RTL;
|