//
// File: vga_graph2_buf.v
// Date: 08-Nov-05
// Author: I. Chuang <ichuang@mit.edu>
//
// VGA display of a 638x256 graph (in a 640x258 window)
//
// This version buffers the input data, and copies it to the display
// each time the input data buffer is filled, after the last display
// of a full buffer is complete.
//
// This version also displays two different buffers (eg for the
// real and imaginary results of a FFT).
module vga_graph2_buf (reset,vclock,pix_clk,hcount,vcount,pixel,
data1,data2,dclk,dstart,cx,cy);
parameter NX = 640; // number of data pixels (horiz size)
parameter GPIX_RGB1 = 3'b111; // pixel RGB for graph data1
parameter GPIX_RGB2 = 3'b100; // pixel RGB for graph data2
input reset; // system reset
input vclock; // system synchronous clock
input pix_clk; // video pixel clock
input [9:0] hcount; // horizontal index of current pixel (0..639)
input [9:0] vcount; // vertical index of current pixel (0..479)
output [2:0] pixel; // char display's pixel
input [9:0] cx; // x-location of graph (upper left corner)
input [9:0] cy; // y-location of graph (upper left corner)
input [7:0] data1; // next data word to clock in
input [7:0] data2; // next data word to clock in
input dclk; // data clock
input dstart; // pulse to start data input
// data is loaded begining with the clock cycle after (the single-cycle)
// dstart signal rises.
reg [7:0] gdat1[NX:0]; // ring buffer memory for display data1
reg [7:0] gdat2[NX:0]; // ring buffer memory for display data2
// pixels for the graph
wire [9:0] hoff = hcount-cx;
reg [9:0] hptr;
always @(posedge vclock)
hptr <= (hoff==0) ? 11'b0 // start display pointer at zero
: ~pix_clk ? hptr
: (hptr == NX-1 ? 0 : hptr+1);
wire [9:0] voff = vcount - cy;
wire [2:0] gpix = ( ((voff==gdat1[hptr]) ? GPIX_RGB1 : 3'b0)
| ((voff==gdat2[hptr]) ? GPIX_RGB2 : 3'b0) );
// clocking in new data
reg [7:0] vdat1[NX:0]; // ring buffer memory for incoming data1
reg [7:0] vdat2[NX:0]; // ring buffer memory for incoming data2
reg [10:0] buf_cnt; // counter on current size of new sample buf
reg [10:0] cp_cnt; // count of samples copied to display buffer
reg loading;
reg [1:0] view_cycle; // number of vid frames after copy_done raised
wire end_buf = (buf_cnt==NX);
wire frame_over = (vcount == 478) & (hcount == 1) & pix_clk;
wire copy_flag = loading & end_buf; // copy requested
wire view_done = (view_cycle==2); // new data displayed
wire copy_done = (cp_cnt == NX) ? 1 : 0; // copy done
wire new_set = copy_done & view_done; // req new set of data
// loop which makes sure a full video frame is displayed after
// loaded data is copied to display buffer, before new sample is taken
always @(posedge vclock)
view_cycle <= (reset | ~copy_done) ? 0
: (copy_done & frame_over) ? view_cycle + 1
: view_cycle;
// main loop which samples data and checks for load request
always @(posedge vclock)
if (reset)
begin
buf_cnt <= 0;
loading <= 0;
end
else if (dclk) // dclk is the clock-enable data clock
begin
loading <= new_set ? 0
: dstart ? 1 // start one cycle after dstart rises
: loading;
buf_cnt <= new_set ? 0
: (loading & ~end_buf) ? buf_cnt + 1
: buf_cnt;
if (loading)
begin
vdat1[buf_cnt] <= 8'd255 - data1; // store data
vdat2[buf_cnt] <= 8'd255 - data2; // store data
end
end
// copy from input buffer to display buffer when loaded & inbuf full
always @(posedge vclock)
begin
// cp_cnt counts up to NX-1 and stays there until copy_flag -> 0
cp_cnt <= copy_flag ? ((cp_cnt < NX) ? cp_cnt + 1 : cp_cnt) : 0;
gdat1[cp_cnt] <= copy_flag ? vdat1[cp_cnt] : gdat1[cp_cnt];
gdat2[cp_cnt] <= copy_flag ? vdat2[cp_cnt] : gdat2[cp_cnt];
end
// border
wire bpixfl = (hoff==0) | (hoff==NX) | (voff==0) | (voff==254);
wire [2:0] bpix = bpixfl ? 3'b010 : 3'b0;
// display flag
wire dispflag = ( (hcount>=cx) & (hcount <= cx+NX) & (vcount >= cy-1) &
(vcount <= (cy+10'd254)) );
// final pixel output
reg [2:0] pixel;
always @(posedge vclock)
pixel <= pix_clk ? (dispflag ? gpix | bpix : 0) : pixel;
endmodule // vga_graph