// Use a blockram to hold the graphical data
wire [7:0] BitmapData;
blockram_8x512 RAM_bitmap(.clk(clk), .rd_adr({CounterY[4:0],CounterX[4:1]}), .data_out(BitmapData));
// Let's say we need 4 bits at a time
wire [3:0] LCD_Bitmap4 = CounterX[0] ? BitmapData[3:0] : BitmapData[7:4];
// Display the data into a chessboard pattern
wire [3:0] LCD_BitmapChessboard = (CounterY[5] ^ CounterX[5]) ? 4'b000 : LCD_Bitmap4 ^ {4{CounterY[5]}};
// We assume CounterX and CounterY are available:
// CounterX is the pixel number of the current line
// CounterY is the line number
// We use a RAM to hold the "Y" values
// Y=F(CounterX)
wire [7:0] RAM_Y_value;
blockram_8x512 RAM_FXY(.clk(clk), .rd_adr(CounterX), .data_out(RAM_Y_value));
// check for equality between the "Y" values and "CounterY"
reg grcpeq1; always @(posedge clk) grcpeq1 <= (RAM_Y_value==CounterY);
reg grcpeq2; always @(posedge clk) grcpeq2 <= grcpeq1;
// check for "greater-than" between the "Y" values and "CounterY"
reg grcp1; always @(posedge clk) grcp1 <= (RAM_Y_value>CounterY);
reg grcp2; always @(posedge clk) grcp2 <= grcp1;
// display a pixel if equality, or if "CounterY" is between 2 successive "Y" values
wire FXpix= grcpeq2 | (grcp1 ^ grcp2);
reg [15:0] X0, Y0, X1, Y1;
always @(posedge clk)
if(Vsync)
begin
X0 <= 0;
Y0 <= 0;
X1 <= 0;
Y1 <= 0;
end
else
if(Hsync)
begin
X0 <= X1 - 100;
Y0 <= Y1 + 400;
X1 <= X1 - 100;
Y1 <= Y1 + 400;
end
else
begin
X0 <= X0 + 400;
Y0 <= Y0 + 100;
end
// Display a chessboard pattern by XOR'ing the MSB of X and Y counters
// You could also display a rotozoomed bitmap by feeding X and Y to a bitmap in a RAM
wire rotozoom_pix = X0[15] ^ Y0[15];
wire [7:0] CharacterRAM_dout;
ram8x2048 CharacterRAM(
.clk(clk),
.rd_adr({CounterY[7:3],CounterX[6:1]}),
.data_out(CharacterRAM_dout)
);
wire [7:0] raster8;
rom8x2048 FontROM(
.clk(clk),
.rd_adr({CharacterRAM_dout, CounterY[2:0]}),
.data_out(raster8)
);
wire [3:0] LCDdata = CounterX[0] ? raster8[7:4] : raster8[3:0];
wire [3:0] charfont0, charfont1;
always @(posedge clk)
begin
case(cnt_mod3)
2'b00: LCDdata <= charfont0;
2'b01: LCDdata <= {charfont0[3:2], charfont1[3:2]};
2'b10: LCDdata <= {charfont1[3:2], charfont0[1:0]};
endcase
end
reg [1:0] cnt_mod3;
always @(posedge clk) if(cnt_mod3==2) cnt_mod3 <= 0; else cnt_mod3 <= cnt_mod3 + 1;
// character-counter (increments only twice every 3 clocks)
reg [6:0] cnt_charbuf;
always @(posedge clk) if(cnt_mod3!=1) cnt_charbuf <= cnt_charbuf + 1;
wire [11:0] CharacterRAM_rdaddr = CounterY[8:3]*80 + cnt_charbuf;
wire [7:0] CharacterRAM_dout;
ram8x2048 CharacterRAM(
.clk(clk),
.rd_adr(CharacterRAM_rdaddr),
.data_out(CharacterRAM_dout)
);
// remember the previous character displayed
reg [7:0] RAM_charbuf_dout_last;
always @(posedge clk) CharacterRAM_dout_last <= CharacterRAM_dout;
// because we need it when we display 2 half characters at once
wire [10:0] readaddr0 = {CharacterRAM_dout, CounterY[2:0]};
wire [10:0] readaddr1 = {CharacterRAM_dout_last, CounterY[2:0]};
// The font ROMs are split in two blockrams, holding 4 pixels each
// (half of the second ROM is not used, since we need only 6 pixels)
rom4x2048 FontROM0(.clk(clk), .rd_adr(readaddr0), .data_out(charfont0));
rom4x2048 FontROM1(.clk(clk), .rd_adr(readaddr1), .data_out(charfont1));
reg [5:0] cnt_cursorblink;
always @(posedge clk) if(vsync & hsync) cnt_cursorblink <= cnt_cursorblink + 1;
wire cursorblinkstate = cnt_cursorblink[5]; // cursor on for 32 frames, off for 32 frames
// Do we have a cursor-character match?
wire cursorblink_adrmatch = cursorblinkstate & (CharacterRAM_rdaddr==CursorAddress);
// When we have a match, "invert" the character
// First for charfont0
wire [3:0] charfont0_cursor = charfont0 ^ {4{cursorblink_adrmatch}};
// Next for charfont1
reg cursorblink_adrmatch_last;
always @(posedge clk) cursorblink_adrmatch_last <= cursorblink_adrmatch;
wire [3:0] charfont1_cursor = charfont1 ^ {4{cursorblink_adrmatch_last}};