Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- MINIMAL GB BOY COLOUR VGA OUTPUT
- VHDL MODEL(?)
- Should be able to run on any FPGA/
- CPLD with enough logic elements and
- ~1 kilobyte of built-in RAM, as well
- as being able to run off of ~25MHz
- for memory access
- Will be running on Altera Cyclone II EP2C5
- $20 cheap ass dev board
- Notes for coding here!
- Ignore them, I copied them because I'm a retard at VHDL :p
- ENTITY <entity_name> IS
- generic declarations
- port declarations = inputs and outputs
- Port declaration format-
- <class> object_name: <mode> <type>;
- <class> = what can be done to an object
- object_name = identifier
- <mode> = direction (in (input), out (output),
- inout (bidirectional), buffer (output w/internal
- feedback))
- <type> = what can be contained in the object
- Generic (entity) declaration-
- Considered a statement and ends with a semicolon
- Each statement in generic ends with semicolon
- Architecture
- Analogy/schematic- describes the functionality/timing of model
- Must be associated with an ENTITY
- ARCHITECTURE statements execute concurrently (processes)
- ARCHITECTURE styles:
- Behavioral- how designs operate
- RTL: designs are described in terms of registers
- Functional: no timing
- Structural- netlist
- Gate/component level
- Hybrid- mixture of the two styles
- End architecture with:
- END ARCHITECTURE <architecture_name>; VHDL '93 and later
- END ARCHITECTURE; VHDL '93 and later
- END; all VHDL versions
- ARCHITECTURE <identifier> OF <identity_identifier> IS
- Component declarations
- Subtype declarations
- Attribute declarations
- Attribute specifications
- Subprogram declarations
- Subprogram body
- BEGIN (architecture body)
- Process statements
- Concurrent procedural calls
- Concurrent signal alignment
- Component instantiation statements
- Generate statements
- END ARCHITECTURE <identifier>;
- Configuration
- CONFIGURATION <identifier> OF <entity_name> IS
- FOR <architecture_name>
- FOR <instance_name> : <component_name> USE <entity>(<architecture>)
- END FOR;
- FOR <instance_name> : <component_name> USE <configuration_name>
- END FOR;
- END FOR;
- END CONFIGURATION <identifier>;
- PUTTING IT TOGETHER:
- -ENTITY defines ports
- -ARCHITECTURE defines behavior
- -CONFIGURATION ties the ENTITY and ARCHITECTURE together
- BEHAVIORAL SUMMARY OF ADAPTER (NOT VHDL):
- Modules:
- Input (counter) module
- -Consists of counter from 0 to 159
- -Counts up on rising edge of pixel clock
- -Counter output determines address of RAM
- to write input pixel data to
- RAM module
- -Consists of 2 15-bit, 160-word banks
- -Muxes on each side that allow access to
- opposing banks of RAM for input/output
- -Valid data on input latches on falling edge
- of pixel clock(?)
- -RAM bank muxes switch access on falling
- edge of Gameboy's horizontal sync
- Output enable and sync module
- -Consists of 1 counter that counts from
- 0 to 227
- -Counter's clock is the core 25.175MHz
- clock divided by 3
- -Contains logic to control other counters
- and generate sync using output enable
- (when during the count is the address counter
- supposed to be working, and general horizontal
- sync generation)
- -OE logic: there are ~180 total active display pixels,
- so wait 10 pixels to start outputting (10-169)
- -Also contains carry output for vertical line counter
- Buffer read/video output module
- -Consists of 1 counter going from 0 to 159
- -Clocked at 25.175MHz divided by 3 (8.3916MHz; clock
- is derived from GB Boy Colour's FPGA clock output,
- which is a test pad above it)
- -Counts up only when it receives a high output enable
- signal from the OE/sync module
- -Outputs directly to VGA only when vertical output
- enable and horizontal output enable are high
- Vertical sync module
- -Consists of 1 counter going from 0 to 615
- -Resets on falling edge of Gameboy's vertical sync
- -Active output is shifted by 1 line so it is always
- 1 line behind the Gameboy (because of the buffer)
- (line 616 is essentially equal to line 1, difference
- will be made by vertical sync generation logic)
- -Has logic that generates vertical sync output and
- the active picture enable line for the video output
- module
- -VSync logic: include line 0 in blanking interval,
- active lines are 1 to 576, 577 to 615 are blanking
- */
- library ieee;
- use ieee.std_logic_1164.all;
- use ieee.numeric_std.all;
- -- Video Input / System Pins
- -- 18 25MHz clock from GBBC
- -- 42 VSync
- -- 43 HSync
- -- 40 Pixel clock
- -- 44 LDR0
- -- 45 LDR1
- -- 47 LDR2
- -- 48 LDR3
- -- 51 LDR4
- -- 53 LDG0
- -- 55 LDG1
- -- 57 LDG2
- -- 58 LDG3
- -- 59 LDG4
- -- 63 LDB0
- -- 64 LDB1
- -- 65 LDB2
- -- 67 LDB3
- -- 69 LDB4
- -- Video Output Pins
- -- 112 VSync
- -- 113 HSync
- -- 114 R0
- -- 115 R1
- -- 118 R2
- -- 119 R3
- -- 120 R4
- -- 122 G0
- -- 125 G1
- -- 126 G2
- -- 129 G3
- -- 132 G4
- -- 134 B0
- -- 135 B1
- -- 136 B2
- -- 137 B3
- -- 139 B4
- entity gameboy_vga is
- port(
- VinVSync : in std_logic;
- VinHSync : in std_logic;
- VinClock : in std_logic;
- VinData : in std_logic_vector(14 downto 0);
- VoutVSync : out std_logic := '1';
- VoutHSync : out std_logic := '1';
- VoutData : out std_logic_vector(14 downto 0) := "000000000000000";
- SourceClock: in std_logic
- );
- end gameboy_vga;
- architecture Behavioral of gameboy_vga is
- -- dual line buffer, 160 pixels per line, 15 bits per pixel
- type video_ram_matrix is array (0 to 319) of std_logic_vector(14 downto 0);
- shared variable video_ram: video_ram_matrix;
- shared variable ram_bank : integer := 0;
- shared variable in_ram_bank : integer := 1;
- shared variable out_ram_bank: integer := 0;
- signal VoutClock: std_logic;
- signal FakeReset: std_logic; -- not connected to anything
- signal FakeClock: std_logic;
- component pll is
- port (
- pll_input_clock_clk : in std_logic := 'X'; -- clock in
- pll_reset_reset : in std_logic := 'X'; -- reset
- pll_output_clock_clk : out std_logic -- clock out
- );
- end component pll;
- begin
- FakeClock <= VinClock or VinHSync;
- u0: component pll port map (
- pll_input_clock_clk => SourceClock, -- This should be the 25MHz clock from GBBC
- pll_reset_reset => FakeReset,
- pll_output_clock_clk => VoutClock
- );
- process (FakeClock)
- variable ram_cell: integer range 0 to 159 := 0;
- begin
- if falling_edge(FakeClock) then
- video_ram(ram_cell + in_ram_bank) := VinData;
- ram_cell := ram_cell + 1;
- if (ram_cell > 159)
- ram_cell := 0;
- end if;
- end process;
- process (VinHSync) begin
- if rising_edge(VinHSync) then -- to switch the RAM banks; just adds an offset
- if(ram_bank = 0)
- out_ram_bank := ram_bank;
- ram_bank := 160;
- in_ram_bank := ram_bank;
- else
- out_ram_bank := ram_bank;
- ram_bank := 0;
- in_ram_bank := ram_bank;
- end if;
- /*
- if(VideoPixel >= 186) -- safe threshold for synchronous reset?
- VideoLine := VideoLine + 1;
- end if;
- VideoPixel := 0;
- VideoRamCell := 0;
- */
- end if;
- end process;
- process (VinVSync) begin
- if falling_edge(VinVSync) then
- VideoLine := 615;
- /*
- VideoPixel := 0;
- VideoRamCell := 0;
- */
- end if;
- end process;
- process (VoutClock)
- -- VESA Signal 768 x 576 @ 60 Hz
- -- http://tinyvga.com/vga-timing/768x576@60Hz
- -- 768 x 576 (976 x 597)
- -- PSYCHE! You really thought it would use a normal resolution?
- -- Screw that, we don't have a framebuffer to waste for GBC!
- -- Calculated as 180 x 576 (228 x 616)
- -- Allows line-by-line buffering to output glorious full color!
- -- No worrying about which line to display since the buffer is synchronous
- -- Pixel clock is 8.3916MHz (25.175MHz/3), from GBBC clock
- -- First replace GBBC's 25MHz crystal with a 25.175MHz one (or not)
- -- Remember: display/vertical sync is offset by 1 to make buffering work properly
- -- Total horizontal blanking area = 48 pixels
- -- Horizontal front porch = 8 pixels
- -- Horizontal sync pulse = 16 pixels
- -- Horizontal back porch = 24 pixels
- -- Total vertical blanking area = 40 lines
- -- Vertical front porch = 20 lines, hopefully this value doesn't goof anything up
- -- Vertical sync pulse = 3 lines
- -- Vertical back porch = 17 lines
- variable hsync_begin_value: integer := 187;
- variable hsync_end_value: integer := 204;
- variable vsync_begin_value: integer := 596;
- variable vsync_end_value: integer := 599;
- shared variable VideoPixel: integer range 0 to 227 := 0;
- shared variable VideoLine: integer range 0 to 615 := 0;
- shared variable VideoRamCell: integer range 0 to 159 := 0;
- begin
- if rising_edge(VoutClock) then
- if (VideoLine < 576)
- if (VideoPixel < 228) then
- if (VideoPixel <= 169) and (VideoPixel >= 10) then -- video data
- VoutData <= video_ram(VideoRamCell + out_ram_bank);
- VideoRamCell := VideoRamCell + 1;
- else
- VoutData <= "000000000000000";
- if (VideoPixel > hsync_begin_value) and (VideoPixel < hsync_end_value) then
- VoutHSync <= '0';
- else
- VoutHSync <= '1';
- end if;
- end if;
- VideoPixel := VideoPixel + 1;
- else
- VideoLine := VideoLine + 1;
- VideoPixel := 0;
- end if;
- else
- VoutData <= "000000000000000";
- end if;
- if (VideoLine > vsync_begin_value and VideoLine < vsync_end_value) then
- VoutVSync <= '1';
- else
- VoutVSync <= '0';
- end if;
- if (VideoLine > 615) then
- VideoLine := 0;
- VideoRamCell := 0;
- end if;
- end if;
- end process;
- end Behavioral;
Add Comment
Please, Sign In to add comment