From 6a8da13e6f1523302051e84552b5d90c2e5a4584 Mon Sep 17 00:00:00 2001 From: Philip Smart Date: Tue, 10 Nov 2020 22:39:10 +0000 Subject: [PATCH] Bug fixes and tweaks --- FPGA/VideoController.vhd | 74 ++++++++++++++++++++++++++----- FPGA/VideoController_Toplevel.vhd | 21 +++++++-- FPGA/build/VideoController.qsf | 2 + FPGA/build/Video_Clock_III.vhd | 18 ++++---- 4 files changed, 92 insertions(+), 23 deletions(-) diff --git a/FPGA/VideoController.vhd b/FPGA/VideoController.vhd index 6ed1595..3a46335 100644 --- a/FPGA/VideoController.vhd +++ b/FPGA/VideoController.vhd @@ -70,6 +70,7 @@ entity VideoController is VIDCLK_65MHZ : in std_logic; -- 65MHz base clock for video timing and gate clocking. VIDCLK_25_175MHZ : in std_logic; -- 25.175MHz base clock for video timing and gate clocking. VIDCLK_40MHZ : in std_logic; -- 40MHz base clock for video timing and gate clocking. + VIDCLK_PSEUDO : in std_logic; -- Clock to create pixel slicing to generate pseudo monochrome. -- V[name] = Voltage translated signals which mirror the mainboard signals but at a lower voltage. -- Address Bus @@ -377,6 +378,8 @@ architecture rtl of VideoController is signal V_I_SYNC_END : unsigned(15 downto 0); signal V_I_LINE_END : unsigned(15 downto 0); signal DISABLE_INT_DISPLAY : std_logic; + signal PSEUDOGREY_VIDEO : std_logic; -- Pseudo grey video stream. + signal PSEUDOGREY_CTR : integer range 0 to 7; -- Counter to create video signal sub divisions. -- -- CG-ROM -- @@ -747,7 +750,7 @@ begin -- Every time we reach the end of the visible display area we enable copying of the VRAM and GRAM into the -- display framebuffer, ready for the next frame display. This starts to occur a fixed set of rows after - -- they have been displayed, initially only during the hblank period of a row, but the during the full row + -- they have been displayed, initially only during the hblank period of a row, but during the full row -- in the vblank period. -- if V_COUNT = 0 then @@ -2392,7 +2395,7 @@ begin else GRAM_DO_GII when VZ80_RDn = '0' and CS_GRAMn = '0' and GRAM_OPT_WRITE = '1' -- For MZ80B GRAM II memory read - lower 8K of blue framebuffer. else - V_BLANKi & H_BLANKi & VIDEO_MODE_REG(5 downto 0)when VZ80_RDn = '0' and CS_FB_VMn = '0' + VIDEO_MODE_REG(7 downto 0) when VZ80_RDn = '0' and CS_FB_VMn = '0' else GRAM_MODE_REG when VZ80_RDn = '0' and CS_FB_CTLn = '0' else @@ -2402,7 +2405,7 @@ begin else GRAM_B_FILTER when VZ80_RDn = '0' and CS_FB_BLUEn = '0' else - PAGE_MODE_REG when VZ80_RDn = '0' and CS_FB_PAGEn = '0' + PAGE_MODE_REG(7) & V_BLANKi & H_BLANKi & PAGE_MODE_REG(4 downto 0) when VZ80_RDn = '0' and CS_FB_PAGEn = '0' else CGROM_DO when VZ80_RDn = '0' and CS_DXXXn = '0' and CGROM_PAGE = '1' else @@ -2697,6 +2700,55 @@ begin -- end if; -- end process; + -- Pseudo greyscale monochrome generator. + -- The internal monitor only supports on/off pixels so representing colour or grey scale cannot be done. This process, based on the colour attribute, pulses the pixels, skipping some pulses depending on colour + -- to give the effect of grey scaling. + process(VIDCLK_PSEUDO, VRESETn) + begin + -- Ensure default values at reset. + if VRESETn='0' then + PSEUDOGREY_CTR <= 0; + PSEUDOGREY_VIDEO <= '0'; + + elsif rising_edge(VIDCLK_PSEUDO) then + + -- Always reset the pulse every clock tick, so 1 pulse = 1/VIDCLK_PSEUDO wide. + -- + PSEUDOGREY_VIDEO <= '0'; + + -- Rotate the counter, the value determines when a pulse is output according to the colour pixel being displayed. + PSEUDOGREY_CTR <= PSEUDOGREY_CTR + 1; + + if SR_R_DATA(7) = '1' and SR_G_DATA(7) = '1' and SR_B_DATA(7) = '1' then + PSEUDOGREY_VIDEO <= '1'; + + elsif SR_R_DATA(7) = '1' and SR_G_DATA(7) = '1' and SR_B_DATA(7) = '0' and (PSEUDOGREY_CTR = 1 or PSEUDOGREY_CTR = 2 or PSEUDOGREY_CTR = 4 or PSEUDOGREY_CTR = 5 or PSEUDOGREY_CTR = 6 or PSEUDOGREY_CTR = 7) then + PSEUDOGREY_VIDEO <= '1'; + + elsif SR_R_DATA(7) = '1' and SR_G_DATA(7) = '0' and SR_B_DATA(7) = '1' and (PSEUDOGREY_CTR = 2 or PSEUDOGREY_CTR = 4 or PSEUDOGREY_CTR = 5 or PSEUDOGREY_CTR = 6 or PSEUDOGREY_CTR = 7) then + PSEUDOGREY_VIDEO <= '1'; + + elsif SR_R_DATA(7) = '1' and SR_G_DATA(7) = '0' and SR_B_DATA(7) = '0' and (PSEUDOGREY_CTR = 1 or PSEUDOGREY_CTR = 4 or PSEUDOGREY_CTR = 5 or PSEUDOGREY_CTR = 7) then + PSEUDOGREY_VIDEO <= '1'; + + elsif SR_R_DATA(7) = '0' and SR_G_DATA(7) = '1' and SR_B_DATA(7) = '1' and (PSEUDOGREY_CTR = 2 or PSEUDOGREY_CTR = 4 or PSEUDOGREY_CTR = 6 ) then + PSEUDOGREY_VIDEO <= '1'; + + elsif SR_R_DATA(7) = '0' and SR_G_DATA(7) = '1' and SR_B_DATA(7) = '0' and (PSEUDOGREY_CTR = 4 or PSEUDOGREY_CTR = 5) then + PSEUDOGREY_VIDEO <= '1'; + + elsif SR_R_DATA(7) = '0' and SR_G_DATA(7) = '0' and SR_B_DATA(7) = '1' and (PSEUDOGREY_CTR = 4) then + PSEUDOGREY_VIDEO <= '1'; + end if; + + -- During blanking periods. clear the video stream and reset counter ready for next line to keep things consistent. + if H_BLANKi = '1' or V_BLANKi = '1' then + PSEUDOGREY_VIDEO <= '0'; + PSEUDOGREY_CTR <= 0; + end if; + end if; + end process; + -- Set the mainboard video state, 0 = enabled, 1 = disabled. MODE_CPLD_MB_VIDEOn <= CPLD_CFG_DATA(3); @@ -2734,19 +2786,21 @@ begin -- Mainboard Video output circuitry. This is the emulation of the MB14298/MB14299 gate arrays. We inject the video (serialised data) and the sync/blanking signals into the MB14298 socket -- and these are combined on the mainboard to generate the internal monitor signals. -- - VSRVIDEO_OUT <= (SR_R_DATA(7) xor SR_B_DATA(7)) or (SR_R_DATA(7) xor SR_G_DATA(7)) or (SR_B_DATA(7) xor SR_G_DATA(7)) when DISABLE_INT_DISPLAY = '0' -- Video out from 74LS165 on mainboard, pre-GATE. + VSRVIDEO_OUT <= SR_G_DATA(7) when DISABLE_INT_DISPLAY = '0' and (MODE_VIDEO_MONO = '1' or MODE_VIDEO_MONO80 = '1') + else + PSEUDOGREY_VIDEO when DISABLE_INT_DISPLAY = '0' -- Video out from 74LS165 on mainboard, pre-GATE. else '0'; - VHBLNK_OUTn <= not H_BLANKi when DISABLE_INT_DISPLAY = '0' -- Horizontal blanking. + VHBLNK_OUTn <= not H_BLANKi when DISABLE_INT_DISPLAY = '0' -- Horizontal blanking. else H_I_BLANKi; - VHSY_OUT <= not H_SYNCni when DISABLE_INT_DISPLAY = '0' -- Horizontal Sync. + VHSY_OUT <= not H_SYNCni when DISABLE_INT_DISPLAY = '0' -- Horizontal Sync. else H_I_SYNCni; - VSYNCH_OUT <= not V_SYNCni when DISABLE_INT_DISPLAY = '0' -- Veritcal Sync. + VSYNCH_OUT <= not V_SYNCni when DISABLE_INT_DISPLAY = '0' -- Veritcal Sync. else V_I_SYNCni; - VVBLNK_OUTn <= not V_BLANKi when DISABLE_INT_DISPLAY = '0' -- Vertical blanking. + VVBLNK_OUTn <= not V_BLANKi when DISABLE_INT_DISPLAY = '0' -- Vertical blanking. else V_I_BLANKi; -- Composite video signal output. Composite video is formed in hardware by the combination of VGA R/G/B signals. - CSYNCn <= not (H_SYNCni or V_SYNCni); - CSYNC <= H_SYNCni or V_SYNCni; + CSYNCn <= not (H_SYNCni xor V_SYNCni); + CSYNC <= H_SYNCni xor V_SYNCni; end architecture rtl; diff --git a/FPGA/VideoController_Toplevel.vhd b/FPGA/VideoController_Toplevel.vhd index c6c7649..5607aad 100644 --- a/FPGA/VideoController_Toplevel.vhd +++ b/FPGA/VideoController_Toplevel.vhd @@ -85,10 +85,12 @@ architecture rtl of VideoControllerFPGA is signal VIDCLK_25_175MHZ : std_logic; signal VIDCLK_40MHZ : std_logic; signal VIDCLK_65MHZ : std_logic; + signal VIDCLK_PSEUDO : std_logic; signal PLL_LOCKED : std_logic; signal PLL_LOCKED2 : std_logic; + signal PLL_LOCKED3 : std_logic; signal RESETn : std_logic; - signal RESET_COUNTER : unsigned(1 downto 0); + signal RESET_COUNTER : unsigned(5 downto 0); begin -- Instantiate a PLL to generate the system clock and base video clocks. @@ -97,7 +99,7 @@ begin port map ( inclk0 => CLOCK_50, - areset => not VRESETn, + areset => '0', c0 => SYS_CLK, c1 => IF_CLK, c2 => VIDCLK_8MHZ, @@ -117,6 +119,16 @@ begin locked => PLL_LOCKED2 ); + -- Instantiate a 3rd PLL to generate clock for pseudo monochrome generation on internal monitor. + VCPLL3 : entity work.Video_Clock_III + port map + ( + inclk0 => CLOCK_50, + areset => not VRESETn, + c0 => VIDCLK_PSEUDO, + locked => PLL_LOCKED3 + ); + -- Add the Serial Flash Loader megafunction to enable in-situ programming of the EPCS16 configuration memory. -- SFL : entity work.sfl @@ -139,6 +151,7 @@ begin VIDCLK_65MHZ => VIDCLK_65MHZ, -- 65MHz base clock for video timing and gate clocking. VIDCLK_25_175MHZ => VIDCLK_25_175MHZ, -- 25.175MHz base clock for video timing and gate clocking. VIDCLK_40MHZ => VIDCLK_40MHZ, -- 40MHz base clock for video timing and gate clocking. + VIDCLK_PSEUDO => VIDCLK_PSEUDO, -- Clock to create pixel slicing to generate pseudo monochrome. -- V[name] = Voltage translated signals which mirror the mainboard signals but at a lower voltage. -- Addres Bus @@ -179,12 +192,12 @@ begin -- Process to reset the FPGA based on the external RESET trigger, PLL's being locked -- and a counter to set minimum width. -- - FPGARESET: process(VRESETn, CLOCK_50, PLL_LOCKED, PLL_LOCKED2) + FPGARESET: process(VRESETn, CLOCK_50, PLL_LOCKED, PLL_LOCKED2, PLL_LOCKED3) begin if VRESETn = '0' then RESET_COUNTER <= (others => '1'); RESETn <= '0'; - elsif PLL_LOCKED = '1' and PLL_LOCKED2 = '1' then + elsif PLL_LOCKED = '1' and PLL_LOCKED2 = '1' and PLL_LOCKED3 = '1' then if rising_edge(CLOCK_50) then if RESET_COUNTER /= 0 then RESET_COUNTER <= RESET_COUNTER - 1; diff --git a/FPGA/build/VideoController.qsf b/FPGA/build/VideoController.qsf index a5972db..202b15a 100644 --- a/FPGA/build/VideoController.qsf +++ b/FPGA/build/VideoController.qsf @@ -264,6 +264,7 @@ set_global_assignment -name VHDL_FILE ../VideoController_Toplevel.vhd set_global_assignment -name QIP_FILE SFL.qip set_global_assignment -name QIP_FILE Video_Clock.qip set_global_assignment -name QIP_FILE Video_Clock_II.qip +set_global_assignment -name QIP_FILE Video_Clock_III.qip set_global_assignment -name QIP_FILE vbuffer.qip set_global_assignment -name VHDL_FILE ../VideoController_pkg.vhd set_global_assignment -name VHDL_FILE ../VideoController.vhd @@ -280,4 +281,5 @@ set_global_assignment -name SDC_FILE VideoController_constraints.sdc + set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/FPGA/build/Video_Clock_III.vhd b/FPGA/build/Video_Clock_III.vhd index 20aff2e..a28bb07 100644 --- a/FPGA/build/Video_Clock_III.vhd +++ b/FPGA/build/Video_Clock_III.vhd @@ -140,12 +140,12 @@ BEGIN altpll_component : altpll GENERIC MAP ( bandwidth_type => "LOW", - clk0_divide_by => 4800, + clk0_divide_by => 25, clk0_duty_cycle => 50, - clk0_multiply_by => 1007, + clk0_multiply_by => 64, clk0_phase_shift => "0", compensate_clock => "CLK0", - inclk0_input_frequency => 8333, + inclk0_input_frequency => 20000, intended_device_family => "Cyclone III", lpm_hint => "CBX_MODULE_PREFIX=Video_Clock_III", lpm_type => "altpll", @@ -227,7 +227,7 @@ END SYN; -- Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "8" -- Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "1" -- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" --- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "25.174999" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "128.000000" -- Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" -- Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" -- Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" @@ -235,7 +235,7 @@ END SYN; -- Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" -- Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" -- Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" --- Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "120.000" +-- Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "50.000" -- Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" -- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" -- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" @@ -252,7 +252,7 @@ END SYN; -- Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" -- Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "1" -- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" --- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "25.17500000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "128.00000000" -- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "1" -- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" -- Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" @@ -291,12 +291,12 @@ END SYN; -- Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" -- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all -- Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "LOW" --- Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "4800" +-- Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "25" -- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" --- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "1007" +-- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "64" -- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" -- Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" --- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "8333" +-- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "20000" -- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III" -- Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" -- Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL"