jbshelton

GB Boy Colour VGA out?

Feb 27th, 2021 (edited)
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  
  3.     MINIMAL GB BOY COLOUR VGA OUTPUT
  4.     VHDL MODEL(?)
  5.  
  6.     Should be able to run on any FPGA/
  7.     CPLD with enough logic elements and
  8.     ~1 kilobyte of built-in RAM, as well
  9.     as being able to run off of ~25MHz
  10.     for memory access
  11.  
  12.     Will be running on Altera Cyclone II EP2C5
  13.     $20 cheap ass dev board
  14.  
  15.     Notes for coding here!
  16.     Ignore them, I copied them because I'm a retard at VHDL :p
  17.  
  18.     ENTITY <entity_name> IS
  19.         generic declarations
  20.         port declarations = inputs and outputs
  21.  
  22.         Port declaration format-
  23.             <class> object_name: <mode> <type>;
  24.             <class> = what can be done to an object
  25.             object_name = identifier
  26.             <mode> = direction (in (input), out (output),
  27.             inout (bidirectional), buffer (output w/internal
  28.             feedback))
  29.             <type> = what can be contained in the object
  30.  
  31.         Generic (entity) declaration-
  32.             Considered a statement and ends with a semicolon
  33.             Each statement in generic ends with semicolon
  34.  
  35.     Architecture
  36.         Analogy/schematic- describes the functionality/timing of model
  37.         Must be associated with an ENTITY
  38.         ARCHITECTURE statements execute concurrently (processes)
  39.         ARCHITECTURE styles:
  40.             Behavioral- how designs operate
  41.                 RTL: designs are described in terms of registers
  42.                 Functional: no timing
  43.             Structural- netlist
  44.                 Gate/component level
  45.             Hybrid- mixture of the two styles
  46.  
  47.         End architecture with:
  48.             END ARCHITECTURE <architecture_name>; VHDL '93 and later
  49.             END ARCHITECTURE; VHDL '93 and later
  50.             END; all VHDL versions
  51.  
  52.         ARCHITECTURE <identifier> OF <identity_identifier> IS
  53.             Component declarations
  54.             Subtype declarations
  55.             Attribute declarations
  56.             Attribute specifications
  57.             Subprogram declarations
  58.             Subprogram body
  59.         BEGIN (architecture body)
  60.             Process statements
  61.             Concurrent procedural calls
  62.             Concurrent signal alignment
  63.             Component instantiation statements
  64.             Generate statements
  65.         END ARCHITECTURE <identifier>;
  66.  
  67.         Configuration
  68.             CONFIGURATION <identifier> OF <entity_name> IS
  69.                 FOR <architecture_name>
  70.                     FOR <instance_name> : <component_name> USE <entity>(<architecture>)
  71.                     END FOR;
  72.                     FOR <instance_name> : <component_name> USE <configuration_name>
  73.                     END FOR;
  74.                 END FOR;
  75.             END CONFIGURATION <identifier>;
  76.  
  77.     PUTTING IT TOGETHER:
  78.     -ENTITY defines ports
  79.     -ARCHITECTURE defines behavior
  80.     -CONFIGURATION ties the ENTITY and ARCHITECTURE together
  81.  
  82.  
  83.  
  84.     BEHAVIORAL SUMMARY OF ADAPTER (NOT VHDL):
  85.     Modules:
  86.         Input (counter) module
  87.             -Consists of counter from 0 to 159
  88.             -Counts up on rising edge of pixel clock
  89.             -Counter output determines address of RAM
  90.              to write input pixel data to
  91.         RAM module
  92.             -Consists of 2 15-bit, 160-word banks
  93.             -Muxes on each side that allow access to
  94.              opposing banks of RAM for input/output
  95.             -Valid data on input latches on falling edge
  96.              of pixel clock(?)
  97.             -RAM bank muxes switch access on falling
  98.              edge of Gameboy's horizontal sync
  99.         Output enable and sync module
  100.             -Consists of 1 counter that counts from
  101.              0 to 227
  102.             -Counter's clock is the core 25.175MHz
  103.              clock divided by 3
  104.             -Contains logic to control other counters
  105.              and generate sync using output enable
  106.              (when during the count is the address counter
  107.              supposed to be working, and general horizontal
  108.              sync generation)
  109.             -OE logic: there are ~180 total active display pixels,
  110.              so wait 10 pixels to start outputting (10-169)
  111.             -Also contains carry output for vertical line counter
  112.         Buffer read/video output module
  113.             -Consists of 1 counter going from 0 to 159
  114.             -Clocked at 25.175MHz divided by 3 (8.3916MHz; clock
  115.              is derived from GB Boy Colour's FPGA clock output,
  116.              which is a test pad above it)
  117.             -Counts up only when it receives a high output enable
  118.              signal from the OE/sync module
  119.             -Outputs directly to VGA only when vertical output
  120.              enable and horizontal output enable are high
  121.         Vertical sync module
  122.             -Consists of 1 counter going from 0 to 615
  123.             -Resets on falling edge of Gameboy's vertical sync
  124.             -Active output is shifted by 1 line so it is always
  125.              1 line behind the Gameboy (because of the buffer)
  126.              (line 616 is essentially equal to line 1, difference
  127.              will be made by vertical sync generation logic)
  128.             -Has logic that generates vertical sync output and
  129.              the active picture enable line for the video output
  130.              module
  131.             -VSync logic: include line 0 in blanking interval,
  132.              active lines are 1 to 576, 577 to 615 are blanking
  133.  
  134.  
  135. */
  136.  
  137. library ieee;
  138. use ieee.std_logic_1164.all;
  139. use ieee.numeric_std.all;
  140.  
  141. -- Video Input / System Pins
  142. -- 18 25MHz clock from GBBC
  143. -- 42 VSync
  144. -- 43 HSync
  145. -- 40 Pixel clock
  146. -- 44 LDR0
  147. -- 45 LDR1
  148. -- 47 LDR2
  149. -- 48 LDR3
  150. -- 51 LDR4
  151. -- 53 LDG0
  152. -- 55 LDG1
  153. -- 57 LDG2
  154. -- 58 LDG3
  155. -- 59 LDG4
  156. -- 63 LDB0
  157. -- 64 LDB1
  158. -- 65 LDB2
  159. -- 67 LDB3
  160. -- 69 LDB4
  161.  
  162. -- Video Output Pins
  163. -- 112 VSync
  164. -- 113 HSync
  165. -- 114 R0
  166. -- 115 R1
  167. -- 118 R2
  168. -- 119 R3
  169. -- 120 R4
  170. -- 122 G0
  171. -- 125 G1
  172. -- 126 G2
  173. -- 129 G3
  174. -- 132 G4
  175. -- 134 B0
  176. -- 135 B1
  177. -- 136 B2
  178. -- 137 B3
  179. -- 139 B4
  180.  
  181.  
  182. entity gameboy_vga is
  183.     port(
  184.         VinVSync  : in std_logic;
  185.         VinHSync  : in std_logic;
  186.         VinClock  : in std_logic;
  187.         VinData   : in std_logic_vector(14 downto 0);
  188.        
  189.         VoutVSync : out std_logic := '1';
  190.         VoutHSync : out std_logic := '1';
  191.         VoutData  : out std_logic_vector(14 downto 0) := "000000000000000";
  192.        
  193.         SourceClock: in std_logic
  194.     );
  195. end gameboy_vga;
  196.  
  197. architecture Behavioral of gameboy_vga is
  198.  
  199.     -- dual line buffer, 160 pixels per line, 15 bits per pixel
  200.     type video_ram_matrix is array (0 to 319) of std_logic_vector(14 downto 0);
  201.     shared variable video_ram: video_ram_matrix;
  202.  
  203.     shared variable ram_bank : integer := 0;
  204.     shared variable in_ram_bank : integer := 1;
  205.     shared variable out_ram_bank: integer := 0;
  206.    
  207.     signal VoutClock: std_logic;
  208.     signal FakeReset: std_logic; -- not connected to anything
  209.  
  210.     signal FakeClock: std_logic;
  211.    
  212.     component pll is
  213.         port (
  214.             pll_input_clock_clk  : in  std_logic := 'X'; -- clock in
  215.             pll_reset_reset      : in  std_logic := 'X'; -- reset
  216.             pll_output_clock_clk : out std_logic         -- clock out
  217.         );
  218.     end component pll;
  219.  
  220. begin
  221.  
  222.     FakeClock <= VinClock or VinHSync;
  223.  
  224.     u0: component pll port map (
  225.         pll_input_clock_clk  => SourceClock, -- This should be the 25MHz clock from GBBC
  226.         pll_reset_reset      => FakeReset,
  227.         pll_output_clock_clk => VoutClock
  228.     );
  229.    
  230.     process (FakeClock)
  231.         variable ram_cell: integer range 0 to 159 := 0;
  232.     begin
  233.         if falling_edge(FakeClock) then
  234.             video_ram(ram_cell + in_ram_bank) := VinData;
  235.             ram_cell := ram_cell + 1;
  236.         if (ram_cell > 159)
  237.             ram_cell := 0;
  238.         end if;
  239.     end process;
  240.  
  241.     process (VinHSync) begin
  242.     if rising_edge(VinHSync) then -- to switch the RAM banks; just adds an offset
  243.         if(ram_bank = 0)
  244.             out_ram_bank := ram_bank;
  245.             ram_bank := 160;
  246.             in_ram_bank := ram_bank;
  247.         else
  248.             out_ram_bank := ram_bank;
  249.             ram_bank := 0;
  250.             in_ram_bank := ram_bank;
  251.         end if;
  252.         /*
  253.         if(VideoPixel >= 186) -- safe threshold for synchronous reset?
  254.             VideoLine := VideoLine + 1;
  255.         end if;
  256.         VideoPixel := 0;
  257.         VideoRamCell := 0;
  258.         */
  259.     end if;
  260.     end process;
  261.  
  262.     process (VinVSync) begin
  263.     if falling_edge(VinVSync) then
  264.         VideoLine := 615;
  265.         /*
  266.         VideoPixel := 0;
  267.         VideoRamCell := 0;
  268.         */
  269.     end if;
  270.     end process;
  271.  
  272.     process (VoutClock)
  273.        
  274.         -- VESA Signal 768 x 576 @ 60 Hz
  275.         -- http://tinyvga.com/vga-timing/768x576@60Hz
  276.         -- 768 x 576 (976 x 597)
  277.         -- PSYCHE! You really thought it would use a normal resolution?
  278.         -- Screw that, we don't have a framebuffer to waste for GBC!
  279.         -- Calculated as 180 x 576 (228 x 616)
  280.         -- Allows line-by-line buffering to output glorious full color!
  281.         -- No worrying about which line to display since the buffer is synchronous
  282.         -- Pixel clock is 8.3916MHz (25.175MHz/3), from GBBC clock
  283.         -- First replace GBBC's 25MHz crystal with a 25.175MHz one (or not)
  284.  
  285.         -- Remember: display/vertical sync is offset by 1 to make buffering work properly
  286.         -- Total horizontal blanking area = 48 pixels
  287.         -- Horizontal front porch = 8 pixels
  288.         -- Horizontal sync pulse = 16 pixels
  289.         -- Horizontal back porch = 24 pixels
  290.         -- Total vertical blanking area = 40 lines
  291.         -- Vertical front porch = 20 lines, hopefully this value doesn't goof anything up
  292.         -- Vertical sync pulse = 3 lines
  293.         -- Vertical back porch = 17 lines
  294.  
  295.         variable hsync_begin_value: integer := 187;
  296.         variable hsync_end_value: integer := 204;
  297.         variable vsync_begin_value: integer := 596;
  298.         variable vsync_end_value: integer := 599;
  299.         shared variable VideoPixel: integer range 0 to 227 := 0;
  300.         shared variable VideoLine: integer range 0 to 615 := 0;
  301.         shared variable VideoRamCell: integer range 0 to 159 := 0;
  302.     begin
  303.         if rising_edge(VoutClock) then
  304.             if (VideoLine < 576)
  305.                 if (VideoPixel < 228) then
  306.                     if (VideoPixel <= 169) and (VideoPixel >= 10) then -- video data
  307.                         VoutData <= video_ram(VideoRamCell + out_ram_bank);
  308.                         VideoRamCell := VideoRamCell + 1;
  309.                     else
  310.                         VoutData <= "000000000000000";
  311.                         if (VideoPixel > hsync_begin_value) and (VideoPixel < hsync_end_value) then
  312.                             VoutHSync <= '0';
  313.                         else
  314.                             VoutHSync <= '1';
  315.                         end if;
  316.                     end if;
  317.                     VideoPixel := VideoPixel + 1;
  318.                 else
  319.                     VideoLine := VideoLine + 1;
  320.                     VideoPixel := 0;
  321.                 end if;
  322.             else
  323.                 VoutData <= "000000000000000";
  324.             end if;
  325.             if (VideoLine > vsync_begin_value and VideoLine < vsync_end_value) then
  326.                 VoutVSync <= '1';
  327.             else
  328.                 VoutVSync <= '0';
  329.             end if;
  330.             if (VideoLine > 615) then
  331.                 VideoLine := 0;
  332.                 VideoRamCell := 0;
  333.             end if;
  334.         end if;
  335.     end process;
  336.    
  337. end Behavioral;
Add Comment
Please, Sign In to add comment