OpenCores
URL https://opencores.org/ocsvn/cpu8080/cpu8080/trunk

Subversion Repositories cpu8080

[/] [cpu8080/] [trunk/] [project/] [vga.vhd.save] - Blame information for rev 33

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 20 samiam9512
-- *****************************************************************************
2
-- *                                                                           *
3
-- *                            VGA TIMING DRIVER                              *
4
-- *                                                                           *
5
-- * Creates timing for the VGA port on an XESS board. This is the XESS VGA    *
6
-- * generator with the pixel buffer fifo ripped out, and the signals it fed   *
7
-- * are brought out to ports. The buffer is not bad, it is just not required  *
8
-- * for applications like a dot character generator, that can respond to      *
9
-- * pixel row timing without delay.                                           *
10
-- *                                                                           *
11
-- * Simulation plugs exist in this code. Look for "????? SIMULATION PLUG"     *
12
-- *                                                                           *
13
-- *****************************************************************************
14
 
15
library IEEE, unisim;
16
use IEEE.std_logic_1164.all;
17
use IEEE.numeric_std.all;
18
use unisim.vcomponents.all;
19
use work.common.all;
20
 
21
package vga_pckg is
22
  component vga
23
    generic (
24
      FREQ            :     natural := 50_000;  -- master clock frequency (in KHz)
25
      CLK_DIV         :     natural := 2;  -- FREQ / CLK_DIV = pixel clock
26
      PIXEL_WIDTH     :     natural := 2;  -- pixel width: 1, 2, 4, 8, or 16 bits
27
      PIXELS_PER_LINE :     natural := 640;  -- pixels per video scan line
28
      LINES_PER_FRAME :     natural := 480;  -- scan lines per video frame
29
      NUM_RGB_BITS    :     natural := 3;  -- width of R, G and B color output buses (2 or 3 are only valid values)
30
      FIT_TO_SCREEN   :     boolean := true  -- fit width x length to monitor screen
31
      );
32
    port (
33
      rst             : in  std_logic;  -- reset
34
      clk             : in  std_logic;  -- master clock
35
      pixel_data_in   : in  std_logic_vector(15 downto 0);  -- input databus to pixel buffer
36
      rd              : out std_logic;  -- read next pixel
37
      eof             : out std_logic;  -- end of vga frame
38
      r, g, b         : out std_logic_vector(NUM_RGB_BITS-1 downto 0);  -- R,G,B color output buses
39
      hsync_n         : out std_logic;  -- horizontal sync pulse
40
      vsync_n         : out std_logic;  -- vertical sync pulse
41
      blank           : out std_logic   -- blanking signal
42
      );
43
  end component vga;
44
end package vga_pckg;
45
 
46
library IEEE, unisim;
47
use IEEE.std_logic_1164.all;
48
use IEEE.numeric_std.all;
49
use unisim.vcomponents.all;
50
use work.common.all;
51
 
52
entity vga is
53
  generic (
54
    FREQ            :     natural := 50_000;  -- master clock frequency (in KHz)
55
    CLK_DIV         :     natural := 2;  -- FREQ / CLK_DIV = pixel clock
56
    PIXEL_WIDTH     :     natural := 2;  -- pixel width: 1, 2, 4, 8, or 16 bits
57
    PIXELS_PER_LINE :     natural := 640;  -- pixels per video scan line
58
    LINES_PER_FRAME :     natural := 480;  -- scan lines per video frame
59
    NUM_RGB_BITS    :     natural := 3;  -- width of R, G and B color output buses
60
    FIT_TO_SCREEN   :     boolean := true  -- fit width x length to monitor screen
61
    );
62
  port (
63
    rst             : in  std_logic;  -- reset
64
    clk             : in  std_logic;  -- master clock
65
    pixel_data_in   : in  std_logic_vector(15 downto 0);  -- input databus to pixel buffer
66
    rd              : out std_logic;  -- read next pixel
67
    eof             : out std_logic;  -- end of vga frame
68
    r, g, b         : out std_logic_vector(NUM_RGB_BITS-1 downto 0);  -- R,G,B color output buses
69
    hsync_n         : out std_logic;  -- horizontal sync pulse
70
    vsync_n         : out std_logic;  -- vertical sync pulse
71
    blank           : out std_logic   -- blanking signal
72
    );
73
end entity vga;
74
 
75
architecture vga_arch of vga is
76
  constant NORM : natural := 1000;      -- normalization factor for us * KHz
77
 
78
  -- video timing parameters for FIT_TO_SCREEN mode
79
  constant HSYNC_START_F  : natural := (NORM * PIXELS_PER_LINE * CLK_DIV)/FREQ + 1;  -- start of horiz. sync pulse with a scanline (us)
80
  constant HSYNC_PERIOD_F : natural := HSYNC_START_F + 6;  -- horizontal scanline period (us)
81
  constant HSYNC_WIDTH_F  : natural := 4;  -- width of horiz. sync pulse (us)
82
  constant HSYNC_FREQ_F   : natural := NORM / HSYNC_PERIOD_F;  -- scanline frequency (KHz)
83
  constant VSYNC_START_F  : natural := HSYNC_PERIOD_F * LINES_PER_FRAME + 340;  -- start of vert. sync pulse within a frame (us)
84
  constant VSYNC_PERIOD_F : natural := VSYNC_START_F + 1084;  -- video frame period (us)
85
  constant VSYNC_WIDTH_F  : natural := 64;  -- width of vert. sync pulse (us)
86
 
87
  -- video timing for 31 KHz horizontal, 60 Hz vertical screen refresh
88
  constant HSYNC_START  : natural := 26;  -- start of horiz. sync pulse with a scanline (us)
89
  constant HSYNC_PERIOD : natural := 32;  -- horizontal scanline period (us)
90
  constant HSYNC_WIDTH  : natural := 4;  -- width of horiz. sync pulse (us)
91
  constant HSYNC_FREQ   : natural := NORM / HSYNC_PERIOD;  -- scanline frequency (KHz)
92
  constant VSYNC_START  : natural := 15_700;  -- start of vert. sync pulse within a frame (us)
93
  constant VSYNC_PERIOD : natural := 16_784;  -- video frame period (us)
94
  constant VSYNC_WIDTH  : natural := 64;  -- width of vert. sync pulse (us)
95
 
96
  signal   clk_div_cnt                :     unsigned(7 downto 0);
97
  signal   cke                        :     std_logic;
98
  signal   line_cnt, pixel_cnt        :     unsigned(15 downto 0);  -- current video line and pixel within line
99
  signal   eof_i, eof_x, eof_r        :     std_logic;
100
  signal   v_gate, cke_v_gate         :     std_logic;
101
  signal   h_blank, v_blank, visible  :     std_logic;
102
  constant PIX_PROC_DELAY             :     natural := 3;  -- time delay to read a pixel from the FIFO and colormap it
103
  signal   hsync_x, hsync_r           :     std_logic_vector(PIX_PROC_DELAY downto 1);
104
  signal   blank_x, blank_r           :     std_logic_vector(PIX_PROC_DELAY downto 1);
105
  signal   rd_x, rd_r                 :     std_logic;
106
  signal   pixel                      :     std_logic_vector(PIXEL_WIDTH-1 downto 0);
107
  signal   pixel_data_x, pixel_data_r :     std_logic_vector(15 downto 0);
108
  signal   rgb_x, rgb_r               :     std_logic_vector(3*NUM_RGB_BITS-1 downto 0);
109
 
110
  component sync
111
    generic (
112
      FREQ                            :     natural := 50_000;  -- master clock frequency (in KHz)
113
      PERIOD                          :     natural := 32;  -- period of sync pulse (in us)
114
      START                           :     natural := 26;  -- time sync pulse starts within the period (in us)
115
      WIDTH                           :     natural := 4;  -- width of sync pulse (in us)
116
      VISIBLE                         :     natural := 1024  -- number of visible pixels/line or lines/frame
117
      );
118
    port (
119
      rst                             : in  std_logic;  -- reset
120
      clk                             : in  std_logic;  -- master clock
121
      cke                             : in  std_logic;  -- clock-enable
122
      sync_n                          : out std_logic;  -- sync pulse
123
      gate                            : out std_logic;  -- single-clock pulse at start of sync pulse
124
      blank                           : out std_logic;  -- blanking signal
125
      cnt                             : out unsigned(15 downto 0)  -- output the timing counter value
126
      );
127
  end component sync;
128
 
129
begin
130
 
131
  -- clock divider for reducing the pixel clock rate
132
  process(clk, rst)
133
  begin
134
    if rst = YES then
135
      clk_div_cnt   <= (others => '0');
136
      cke           <= YES;
137
    elsif rising_edge(clk) then
138
      if clk_div_cnt = CLK_DIV-1 then
139
        clk_div_cnt <= (others => '0');
140
        cke         <= YES;
141
      else
142
        clk_div_cnt <= clk_div_cnt + 1;
143
        cke         <= NO;
144
      end if;
145
    end if;
146
  end process;
147
 
148
  -- form read pixel signal
149
  rd <= rd_x and cke;
150
 
151
  -- the clock enable for the vertical sync module is also combined with a gate signal
152
  -- that is generated at the end of every scanline by the horizontal sync module
153
  cke_v_gate <= cke and v_gate;
154
 
155
  -- generate the horizontal and vertical sync pulses for FIT_TO_SCREEN mode
156
  gen_syncs_fit : if FIT_TO_SCREEN = true generate
157
    hsync       : sync
158
      generic map (
159
        FREQ    => FREQ / CLK_DIV,      -- master pixel-clock frequency
160
        PERIOD  => HSYNC_PERIOD_F,      -- scanline period (32 us)
161
        START   => HSYNC_START_F,       -- start of horizontal sync pulse in scan line
162
        WIDTH   => HSYNC_WIDTH_F,       -- width of horizontal sync pulse
163
        VISIBLE => PIXELS_PER_LINE
164
        )
165
      port map (
166
        rst     => rst,
167
        clk     => clk,                 -- master clock
168
        cke     => cke,                 -- a new pixel is output whenever the clock is enabled
169
        sync_n  => hsync_x(1),          -- send pulse through delay line
170
        gate    => v_gate,              -- send gate signal to increment vertical sync pulse generator once per scan line
171
        blank   => h_blank,             -- blanking signal within a scan line
172
        cnt     => pixel_cnt            -- current pixel within the scan line
173
        );
174
 
175
    vsync : sync
176
      generic map (
177
        FREQ    => HSYNC_FREQ_F,        -- scanline frequency
178
        PERIOD  => VSYNC_PERIOD_F,      -- image frame period
179
        START   => VSYNC_START_F,       -- start of vertical sync pulse in frame
180
        WIDTH   => VSYNC_WIDTH_F,       -- width of vertical sync pulse
181
        VISIBLE => LINES_PER_FRAME
182
        )
183
      port map (
184
        rst     => rst,
185
        clk     => clk,                 -- master clock
186
        cke     => cke_v_gate,          -- enable clock once per horizontal scan line
187
        sync_n  => vsync_n,             -- send pulse through delay line
188
        gate    => eof_x,               -- indicate the end of a complete frame
189
        blank   => v_blank,             -- blanking signal within a frame
190
        cnt     => line_cnt             -- current scan line within a frame
191
        );
192
  end generate;
193
 
194
  -- generate the horizontal and vertical sync pulses for 31 KHz horizontal, 60 Hz vertical screen refresh
195
  gen_syncs_nofit : if FIT_TO_SCREEN = false generate
196
    hsync         : sync
197
      generic map (
198
        FREQ    => FREQ / CLK_DIV,      -- master pixel-clock frequency
199
        PERIOD  => HSYNC_PERIOD,        -- scanline period (32 us)
200
        START   => HSYNC_START,         -- start of horizontal sync pulse in scan line
201
        WIDTH   => HSYNC_WIDTH,         -- width of horizontal sync pulse
202
        VISIBLE => PIXELS_PER_LINE
203
        )
204
      port map (
205
        rst     => rst,
206
        clk     => clk,                 -- master clock
207
        cke     => cke,                 -- clock always enabled so there is a new pixel output on every clock pulse
208
        sync_n  => hsync_x(1),          -- send pulse through delay line
209
        gate    => v_gate,              -- send gate signal to increment vertical sync pulse generator once per scan line
210
        blank   => h_blank,             -- blanking signal within a scan line
211
        cnt     => pixel_cnt            -- current pixel within the scan line
212
        );
213
 
214
    vsync : sync
215
      generic map (
216
        FREQ    => HSYNC_FREQ,          -- scanline frequency (KHz)
217
        PERIOD  => VSYNC_PERIOD,        -- image frame period
218
        START   => VSYNC_START,         -- start of vertical sync pulse in frame
219
        WIDTH   => VSYNC_WIDTH,         -- width of vertical sync pulse
220
        VISIBLE => LINES_PER_FRAME
221
        )
222
      port map (
223
        rst     => rst,
224
        clk     => clk,                 -- master clock
225
        cke     => cke_v_gate,          -- enable clock once per horizontal scan line
226
        sync_n  => vsync_n,             -- send pulse through delay line
227
        gate    => eof_x,               -- indicate the end of a complete frame
228
        blank   => v_blank,             -- blanking signal within a frame
229
        cnt     => line_cnt             -- current scan line within a frame
230
        );
231
  end generate;
232
 
233
  eof_i    <= eof_x and not eof_r;      -- shorten end-of-frame signal to a single clock cycle
234
  eof      <= eof_i;
235
 
236
  visible    <= h_blank nor v_blank;    -- pixels are visible when horiz. & vertical blank are inactive
237
  blank_x(1) <= not visible;            -- send blanking signal through delay line
238
 
239
  -- pass the horiz. and vert. syncs and blanking signal through delay lines to compensate for the
240
  -- processing delays incurred by the pixel data
241
  hsync_x(hsync_x'high downto 2) <= hsync_r(hsync_r'high-1 downto 1);
242
  hsync_n                        <= hsync_r(hsync_r'high);
243
  blank_x(blank_x'high downto 2) <= blank_r(blank_r'high-1 downto 1);
244
  blank                          <= blank_r(blank_r'high);
245
 
246
  -- get the current pixel from the word of pixel data or read more pixel data from the buffer
247
  get_pixel : process(visible, pixel_data_in, pixel_data_r, rd_r, pixel_cnt)
248
  begin
249
    rd_x <= NO;                         -- by default, don't read next word of pixel data from the buffer
250
 
251
    -- shift pixel data depending on its width so the next pixel is in the LSBs of the pixel data shift register
252
    case PIXEL_WIDTH is
253
      when 1      =>                    -- 1-bit pixels, 16 per pixel data word
254
        if (visible = YES) and (pixel_cnt(3 downto 0) = 0) then
255
          rd_x       <= YES;            -- read new pixel data from buffer every 16 clocks during visible portion of scan line
256
        end if;
257
        pixel_data_x <= "0" & pixel_data_r(15 downto 1);  -- left-shift pixel data to move next pixel to LSB
258
      when 2      =>                    -- 2-bit pixels, 8 per pixel data word
259
        if (visible = YES) and (pixel_cnt(2 downto 0) = 0) then
260
          rd_x       <= YES;            -- read new pixel data from buffer every 8 clocks during visible portion of scan line
261
        end if;
262
        pixel_data_x <= "00" & pixel_data_r(15 downto 2);  -- left-shift pixel data to move next pixel to LSB
263
      when 4      =>                    -- 4-bit pixels, 4 per pixel data word
264
        if (visible = YES) and (pixel_cnt(1 downto 0) = 0) then
265
          rd_x       <= YES;            -- read new pixel data from buffer every 4 clocks during visible portion of scan line
266
        end if;
267
        pixel_data_x <= "0000" & pixel_data_r(15 downto 4);  -- left-shift pixel data to move next pixel to LSB
268
      when 8      =>                    -- 8-bit pixels, 2 per pixel data word
269
        if (visible = YES) and (pixel_cnt(0 downto 0) = 0) then
270
          rd_x       <= YES;            -- read new pixel data from buffer every 2 clocks during visible portion of scan line
271
        end if;
272
        pixel_data_x <= "00000000" & pixel_data_r(15 downto 8);  -- left-shift pixel data to move next pixel to LSB
273
      when others =>                    -- any other width, then 1 per pixel data word
274
        if (visible = YES) then
275
          rd_x       <= YES;            -- read new pixel data from buffer every clock during visible portion of scan line
276
        end if;
277
        pixel_data_x <= pixel_data_r;
278
    end case;
279
 
280
    -- store the pixel data from the buffer instead of shifting the pixel data
281
    -- if a read operation was initiated in the previous cycle.
282
    if rd_r = YES then
283
      pixel_data_x <= pixel_data_in;
284
    end if;
285
 
286
    -- the current pixel is in the lower bits of the pixel data shift register
287
    pixel <= pixel_data_r(pixel'range);
288
  end process get_pixel;
289
 
290
  -- map the current pixel to RGB values
291
  map_pixel : process(pixel, rgb_r, blank_r)
292
  begin
293
    if NUM_RGB_BITS=2 then
294
    case PIXEL_WIDTH is
295
      when 1          =>                -- 1-bit pixels map to black or white
296
                          rgb_x <= (others => pixel(0));
297
      when 2          =>                -- 2-bit pixels map to black, 2/3 gray, 1/3 gray, and white
298
                          rgb_x <= pixel(1 downto 0) & pixel(1 downto 0) & pixel(1 downto 0);
299
      when 4          =>                -- 4-bit pixels map to 8 colors (ignore MSB)
300
                          rgb_x <= pixel(2) & pixel(2) & pixel(1) & pixel(1) & pixel(0) & pixel(0);
301
      when 8          =>                -- 8-bit pixels map directly to RGB values
302
        rgb_x <= pixel(7 downto 6) & pixel(4 downto 1);
303
      when others     =>                -- 16-bit pixels maps directly to RGB values
304
        rgb_x <= pixel(8) & pixel(7) & pixel(5) & pixel(4) & pixel(2) & pixel(1);
305
    end case;
306
    else -- NUM_RGB_BITS=3
307
    case PIXEL_WIDTH is
308
      when 1          =>                -- 1-bit pixels map to black or white
309
                          rgb_x <= (others => pixel(0));
310
      when 2          =>                -- 2-bit pixels map to black, 5/7 gray, 3/7 gray, and  1/7 gray
311
                          rgb_x <= pixel(1 downto 0) & '0' & pixel(1 downto 0) & '0' & pixel(1 downto 0) & '0';
312
      when 4          =>                -- 4-bit pixels map to 8 colors (ignore MSB)
313
                          rgb_x <= pixel(2) & pixel(2) & pixel(2) & pixel(1) & pixel(1) & pixel(1) & pixel(0) & pixel(0) & pixel(0);
314
      when 8          =>                -- 8-bit pixels map to RGB with reduced resolution in green component
315
        rgb_x <= pixel(7 downto 5) & pixel(4 downto 3) & '0' & pixel(2 downto 0);
316
      when others     =>                -- 16-bit pixels map directly to RGB values
317
        rgb_x <= pixel(8 downto 0);
318
    end case;
319
    end if;
320
 
321
    -- just blank the pixel if not in the visible region of the screen
322
    if blank_r(blank_r'high-1) = YES then
323
      rgb_x <= (others => '0');
324
    end if;
325
 
326
    -- break the pixel into its red, green and blue components
327
    r <= rgb_r(3*NUM_RGB_BITS-1 downto 2*NUM_RGB_BITS);
328
    g <= rgb_r(2*NUM_RGB_BITS-1 downto NUM_RGB_BITS);
329
    b <= rgb_r(NUM_RGB_BITS-1 downto 0);
330
  end process map_pixel;
331
 
332
-- update registers
333
  update : process(rst, clk)
334
  begin
335
    if rst = YES then
336
      eof_r          <= '0';
337
      rd_r           <= NO;
338
      hsync_r        <= (others => '1');
339
      blank_r        <= (others => '0');
340
      pixel_data_r   <= (others => '0');
341
      rgb_r          <= (others => '0');
342
    elsif rising_edge(clk) then
343
      eof_r          <= eof_x;          -- end-of-frame signal goes at full clock rate to external system
344
      if cke = YES then
345
        rd_r         <= rd_x;
346
        hsync_r      <= hsync_x;
347
        blank_r      <= blank_x;
348
        pixel_data_r <= pixel_data_x;
349
        rgb_r        <= rgb_x;
350
      end if;
351
    end if;
352
  end process update;
353
 
354
end architecture vga_arch;
355
 
356
library IEEE, unisim;
357
use IEEE.std_logic_1164.all;
358
use IEEE.numeric_std.all;
359
use unisim.vcomponents.all;
360
use work.common.all;
361
 
362
-- Generate a sync pulse within a waveform PERIOD.
363
-- Also output the value of the counter used for timing so that
364
-- it can be used in generating an address for a video RAM.
365
 
366
entity sync is
367
  generic (
368
    FREQ    :     natural := 100_000;    -- master clock frequency (in KHz)
369
    PERIOD  :     natural := 32;        -- period of sync pulse (in us)
370
    START   :     natural := 26;        -- time sync pulse starts within the period (in us)
371
    WIDTH   :     natural := 4;         -- width of sync pulse (in us)
372
    VISIBLE :     natural := 1024       -- number of visible pixels/line or lines/frame
373
    );
374
  port (
375
    rst     : in  std_logic;            -- reset
376
    clk     : in  std_logic;            -- master clock
377
    cke     : in  std_logic;            -- clock-enable
378
    sync_n  : out std_logic;            -- sync pulse
379
    gate    : out std_logic;            -- single-clock pulse at start of sync pulse
380
    blank   : out std_logic;            -- blanking signal
381
    cnt     : out unsigned(15 downto 0)  -- output the timing counter value
382
    );
383
end entity sync;
384
 
385
architecture sync_arch of sync is
386
  constant NORM             : natural := 1000;  -- normalization factor for us * KHz
387
  constant CYC_PERIOD       : natural := (PERIOD * FREQ)/NORM;  -- sync wave PERIOD in clock cycles
388
  constant CYC_START        : natural := (START * FREQ)/NORM;  -- sync pulse START in cycles
389
  constant CYC_WIDTH        : natural := (WIDTH * FREQ)/NORM;  -- sync pulse WIDTH in cycles
390
  constant CYC_END          : natural := CYC_START + CYC_WIDTH;  -- sync pulse end in cycles
391
  signal   cnt_r, cnt_x     : unsigned(cnt'range);  -- counter for timing sync pulse waveform
392
  signal   sync_r, sync_x   : std_logic;  -- sync register
393
  signal   gate_r, gate_x   : std_logic;  -- gate register
394
  signal   blank_r, blank_x : std_logic;  -- blank register
395
begin
396
 
397
-- increment counter and wrap around to zero at end of period
398
  cnt_x <= (others => '0') when cnt_r = CYC_PERIOD-1 else cnt_r+1;
399
 
400
-- generate sync pulse within waveform period
401
  sync_x <= LO when cnt_r = CYC_START-1 else
402
            HI when cnt_r = CYC_END-1   else
403
            sync_r;
404
  sync_n <= sync_r;
405
 
406
-- generate gate signal at start of sync pulse
407
  gate_x <= YES when cnt_r = CYC_START-1 else NO;
408
  gate   <= gate_r;
409
 
410
-- generate blank signal after initial visible period
411
  blank_x <= YES when cnt_r = VISIBLE-1    else
412
             NO  when cnt_r = CYC_PERIOD-1 else
413
             blank_r;
414
  blank   <= blank_r;
415
 
416
-- output counter value
417
  cnt <= cnt_r;
418
 
419
-- update counter and registers
420
  update : process(rst, clk)
421
  begin
422
    if rst = YES then
423
-- ????? SIMULATION PLUG
424
-- swap this next to place in non-blank cycle
425
-- this allows data to appear in simulation, and only produces a momentary
426
-- glitch in real hardware
427
--      cnt_r     <= (others => '0');
428
      cnt_r     <= "0000000011111111";
429
      sync_r    <= HI;
430
      gate_r    <= NO;
431
-- ????? SIMULATION PLUG
432
-- swap this next to place in non-blank cycle
433
-- this allows data to appear in simulation, and only produces a momentary
434
-- glitch in real hardware
435
--      blank_r   <= YES;
436
      blank_r   <= NO;
437
    elsif rising_edge(clk) then
438
      if cke = YES then
439
        cnt_r   <= cnt_x;
440
        sync_r  <= sync_x;
441
        gate_r  <= gate_x;
442
        blank_r <= blank_x;
443
      end if;
444
    end if;
445
  end process update;
446
 
447
end architecture sync_arch;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.