1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-02-02 14:50:52 +00:00
Files
Gehstock.Mist_FPGA/Computer_MiST/OricInFPGA_MiST/rtl/ula.vhd
2019-07-22 00:02:14 +02:00

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;