wip of the pipeline VGA module. stupid yosys bug, but testbench looks ok

This commit is contained in:
Alan Garfield 2018-02-05 00:12:06 +11:00
parent 2432225d01
commit 20919fa726
9 changed files with 1029 additions and 838 deletions

View File

@ -33,157 +33,11 @@ module apple1_tb;
initial begin
// force core_top.clk_div = 0;
// force core_top.cpu_clken = 0;
// force core_top.hard_reset = 0;
// force core_top.reset_cnt = 0;
// force core_top.my_cpu.arlet_cpu.AB = 0;
// force core_top.my_cpu.arlet_cpu.PC = 0;
// force core_top.my_cpu.arlet_cpu.ABL = 0;
// force core_top.my_cpu.arlet_cpu.ABH = 0;
// force core_top.my_cpu.arlet_cpu.DIHOLD = 0;
// force core_top.my_cpu.arlet_cpu.IRHOLD = 0;
// force core_top.my_cpu.arlet_cpu.IRHOLD_valid = 0;
// force core_top.my_cpu.arlet_cpu.C = 0;
// force core_top.my_cpu.arlet_cpu.Z = 0;
// force core_top.my_cpu.arlet_cpu.I = 0;
// force core_top.my_cpu.arlet_cpu.D = 0;
// force core_top.my_cpu.arlet_cpu.V = 0;
// force core_top.my_cpu.arlet_cpu.N = 0;
// force core_top.my_cpu.arlet_cpu.AI = 0;
// force core_top.my_cpu.arlet_cpu.BI = 0;
// force core_top.my_cpu.arlet_cpu.DO = 0;
// force core_top.my_cpu.arlet_cpu.WE = 0;
// force core_top.my_cpu.arlet_cpu.CI = 0;
// force core_top.my_cpu.arlet_cpu.NMI_edge = 0;
// force core_top.my_cpu.arlet_cpu.regsel = 0;
// force core_top.my_cpu.arlet_cpu.PC_inc = 0;
// force core_top.my_cpu.arlet_cpu.PC_temp = 0;
// force core_top.my_cpu.arlet_cpu.src_reg = 0;
// force core_top.my_cpu.arlet_cpu.dst_reg = 0;
// force core_top.my_cpu.arlet_cpu.index_y = 0;
// force core_top.my_cpu.arlet_cpu.load_reg = 0;
// force core_top.my_cpu.arlet_cpu.inc = 0;
// force core_top.my_cpu.arlet_cpu.write_back = 0;
// force core_top.my_cpu.arlet_cpu.load_only = 0;
// force core_top.my_cpu.arlet_cpu.store = 0;
// force core_top.my_cpu.arlet_cpu.adc_sbc = 0;
// force core_top.my_cpu.arlet_cpu.compare = 0;
// force core_top.my_cpu.arlet_cpu.shift = 0;
// force core_top.my_cpu.arlet_cpu.rotate = 0;
// force core_top.my_cpu.arlet_cpu.backwards = 0;
// force core_top.my_cpu.arlet_cpu.cond_true = 0;
// force core_top.my_cpu.arlet_cpu.cond_code = 0;
// force core_top.my_cpu.arlet_cpu.shift_right = 0;
// force core_top.my_cpu.arlet_cpu.alu_shift_right = 0;
// force core_top.my_cpu.arlet_cpu.op = 0;
// force core_top.my_cpu.arlet_cpu.alu_op = 0;
// force core_top.my_cpu.arlet_cpu.adc_bcd = 0;
// force core_top.my_cpu.arlet_cpu.adj_bcd = 0;
// force core_top.my_cpu.arlet_cpu.bit_ins = 0;
// force core_top.my_cpu.arlet_cpu.plp = 0;
// force core_top.my_cpu.arlet_cpu.php = 0;
// force core_top.my_cpu.arlet_cpu.clc = 0;
// force core_top.my_cpu.arlet_cpu.sed = 0;
// force core_top.my_cpu.arlet_cpu.cli = 0;
// force core_top.my_cpu.arlet_cpu.sei = 0;
// force core_top.my_cpu.arlet_cpu.clv = 0;
// force core_top.my_cpu.arlet_cpu.brk = 0;
// force core_top.my_cpu.arlet_cpu.res = 0;
// force core_top.my_cpu.arlet_cpu.write_register = 0;
// force core_top.my_cpu.arlet_cpu.ADJL = 0;
// force core_top.my_cpu.arlet_cpu.ADJH = 0;
// force core_top.my_cpu.arlet_cpu.NMI_1 = 0;
// force core_top.my_cpu.arlet_cpu.ALU.OUT = 0;
// force core_top.my_cpu.arlet_cpu.ALU.CO = 0;
// force core_top.my_cpu.arlet_cpu.ALU.N = 0;
// force core_top.my_cpu.arlet_cpu.ALU.HC = 0;
// force core_top.my_cpu.arlet_cpu.ALU.AI7 = 0;
// force core_top.my_cpu.arlet_cpu.ALU.BI7 = 0;
// force core_top.my_cpu.arlet_cpu.ALU.temp_logic = 0;
// force core_top.my_cpu.arlet_cpu.ALU.temp_BI = 0;
// force core_top.my_cpu.arlet_cpu.ALU.temp_l = 0;
// force core_top.my_cpu.arlet_cpu.ALU.temp_h = 0;
clk25 = 1'b0;
uart_rx = 1'b1;
rst_n = 1'b0;
#40 rst_n = 1'b1;
// release core_top.clk_div;
// release core_top.cpu_clken;
// release core_top.hard_reset;
// release core_top.reset_cnt;
// release core_top.my_cpu.arlet_cpu.AB;
// release core_top.my_cpu.arlet_cpu.PC;
// release core_top.my_cpu.arlet_cpu.ABL;
// release core_top.my_cpu.arlet_cpu.ABH;
// release core_top.my_cpu.arlet_cpu.DIHOLD;
// release core_top.my_cpu.arlet_cpu.IRHOLD;
// release core_top.my_cpu.arlet_cpu.IRHOLD_valid;
// release core_top.my_cpu.arlet_cpu.C;
// release core_top.my_cpu.arlet_cpu.Z;
// release core_top.my_cpu.arlet_cpu.I;
// release core_top.my_cpu.arlet_cpu.D;
// release core_top.my_cpu.arlet_cpu.V;
// release core_top.my_cpu.arlet_cpu.N;
// release core_top.my_cpu.arlet_cpu.AI;
// release core_top.my_cpu.arlet_cpu.BI;
// release core_top.my_cpu.arlet_cpu.DO;
// release core_top.my_cpu.arlet_cpu.WE;
// release core_top.my_cpu.arlet_cpu.CI;
// release core_top.my_cpu.arlet_cpu.NMI_edge;
// release core_top.my_cpu.arlet_cpu.regsel;
// release core_top.my_cpu.arlet_cpu.PC_inc;
// release core_top.my_cpu.arlet_cpu.PC_temp;
// release core_top.my_cpu.arlet_cpu.src_reg;
// release core_top.my_cpu.arlet_cpu.dst_reg;
// release core_top.my_cpu.arlet_cpu.index_y;
// release core_top.my_cpu.arlet_cpu.load_reg;
// release core_top.my_cpu.arlet_cpu.inc;
// release core_top.my_cpu.arlet_cpu.write_back;
// release core_top.my_cpu.arlet_cpu.load_only;
// release core_top.my_cpu.arlet_cpu.store;
// release core_top.my_cpu.arlet_cpu.adc_sbc;
// release core_top.my_cpu.arlet_cpu.compare;
// release core_top.my_cpu.arlet_cpu.shift;
// release core_top.my_cpu.arlet_cpu.rotate;
// release core_top.my_cpu.arlet_cpu.backwards;
// release core_top.my_cpu.arlet_cpu.cond_true;
// release core_top.my_cpu.arlet_cpu.cond_code;
// release core_top.my_cpu.arlet_cpu.shift_right;
// release core_top.my_cpu.arlet_cpu.alu_shift_right;
// release core_top.my_cpu.arlet_cpu.op;
// release core_top.my_cpu.arlet_cpu.alu_op;
// release core_top.my_cpu.arlet_cpu.adc_bcd;
// release core_top.my_cpu.arlet_cpu.adj_bcd;
// release core_top.my_cpu.arlet_cpu.bit_ins;
// release core_top.my_cpu.arlet_cpu.plp;
// release core_top.my_cpu.arlet_cpu.php;
// release core_top.my_cpu.arlet_cpu.clc;
// release core_top.my_cpu.arlet_cpu.sec;
// release core_top.my_cpu.arlet_cpu.cld;
// release core_top.my_cpu.arlet_cpu.sed;
// release core_top.my_cpu.arlet_cpu.sei;
// release core_top.my_cpu.arlet_cpu.clv;
// release core_top.my_cpu.arlet_cpu.brk;
// release core_top.my_cpu.arlet_cpu.res;
// release core_top.my_cpu.arlet_cpu.write_register;
// release core_top.my_cpu.arlet_cpu.ADJL;
// release core_top.my_cpu.arlet_cpu.ADJH;
// release core_top.my_cpu.arlet_cpu.NMI_1;
// release core_top.my_cpu.arlet_cpu.ALU.OUT;
// release core_top.my_cpu.arlet_cpu.ALU.CO;
// release core_top.my_cpu.arlet_cpu.ALU.N;
// release core_top.my_cpu.arlet_cpu.ALU.HC;
// release core_top.my_cpu.arlet_cpu.ALU.AI7;
// release core_top.my_cpu.arlet_cpu.ALU.BI7;
// release core_top.my_cpu.arlet_cpu.ALU.temp_logic;
// release core_top.my_cpu.arlet_cpu.ALU.temp_BI;
// release core_top.my_cpu.arlet_cpu.ALU.temp_l;
// release core_top.my_cpu.arlet_cpu.ALU.temp_h;
$display("Starting...");
$dumpfile("apple1_top_tb.vcd");
$dumpvars;

2
iverilog/run_vga_tb.sh Executable file
View File

@ -0,0 +1,2 @@
iverilog -DSIM -g2005 -s vga_tb -o vga_tb -c vga_files.txt
vvp vga_tb

4
iverilog/vga_files.txt Normal file
View File

@ -0,0 +1,4 @@
../rtl/vga/vga.v
../rtl/vga/vram.v
../rtl/vga/font_rom.v
vga_tb.v

95
iverilog/vga_tb.v Normal file
View File

@ -0,0 +1,95 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// Description: Top level test bench for apple1_top
//
// Author.....: Niels A. Moseley
// Date.......: 26-1-2018
//
`timescale 1ns/1ps
module vga_tb;
reg clk25, rst, address, w_en, blink_clken;
reg [7:0] din;
wire vga_h_sync, vga_v_sync, vga_red, vga_grn, vga_blu;
//////////////////////////////////////////////////////////////////////////
// Setup dumping of data for inspection
initial begin
clk25 = 1'b0;
rst = 1'b0;
address = 1'b0;
w_en = 1'b0;
blink_clken = 1'b0;
din = 8'd0;
#5
rst = 1'b1;
#5
rst = 1'b0;
$display("Starting...");
$dumpfile("vga_tb.vcd");
$dumpvars;
//#180000
//uart_rx = 1'b0;
//#400
//uart_rx = 1'b1;
//#400
//uart_rx = 1'b0;
//#400
//uart_rx = 1'b1;
//#800
//uart_rx = 1'b0;
//#1600
//uart_rx = 1'b1;
#50000000 $display("Stopping...");
$finish;
end
//////////////////////////////////////////////////////////////////////////
// Clock
always
#20 clk25 = !clk25;
//////////////////////////////////////////////////////////////////////////
// Core of system
vga my_vga (
.clk25(clk25),
.enable(1'b1),
.rst(rst),
.vga_h_sync(vga_h_sync),
.vga_v_sync(vga_v_sync),
.vga_red(vga_red),
.vga_grn(vga_grn),
.vga_blu(vga_blu),
.address(address),
.w_en(w_en),
.din(din),
.blink_clken(blink_clken)
);
endmodule

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,67 @@
000001
000010
000011
000100
000101
000110
000111
001000
001001
001010
001011
001100
001101
001110
001111
010000
010001
010010
010011
010100
010101
010110
010111
011000
011001
011010
011011
011100
011101
011110
011111
100000
100001
100010
100011
100100
100101
100110
100111
101000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000

54
rtl/vga/font_rom.v Normal file
View File

@ -0,0 +1,54 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// Description: 8KB RAM for system
//
// Author.....: Alan Garfield
// Date.......: 3-2-2018
//
module font_rom(
input clk, // clock signal
input [5:0] character, // address bus
input [3:0] pixel, // address of the pixel to output
input [4:0] line, // address of the line to output
output reg out // single pixel from address and pixel pos
);
`ifdef SIM
parameter ROM_FILENAME = "../roms/vga_font.bin";
`else
parameter ROM_FILENAME = "../../roms/vga_font.bin";
`endif
reg [7:0] rom[0:639];
initial
$readmemb(ROM_FILENAME, rom, 0, 639);
// double width of pixel by ignoring bit 0
wire [2:0] pixel_ptr;
assign pixel_ptr = (3'h7 - pixel[3:1]);
// double height of pixel by ignoring bit 0
wire [3:0] line_ptr = line[4:1];
always @(posedge clk)
out <= rom[(character * 10) + {2'd0, line_ptr}][pixel_ptr];
endmodule

View File

@ -10,300 +10,219 @@ module vga(
input address, // address bus
input w_en, // active high write enable strobe
input [7:0] din, // 8-bit data bas (input)
input clr_screen_btn, // active high clear screen button
input blink_clken, // cursor blink enable strobe
output [15:0] debug
input blink_clken // cursor blink enable strobe
);
reg [4:0] c_rom[0:447] /* synthesis syn_ramstyle = "block_ram" */;
initial begin
$readmemb("../../roms/vga_font.bin", c_rom, 0, 447);
end
reg [9:0] vram_r_addr;
reg [9:0] vram_w_addr;
reg vram_r_en;
reg vram_w_en;
reg [5:0] vram_din;
reg [5:0] vram_dout;
vram my_vram(
.clk(clk25),
.read_addr(vram_r_addr),
.write_addr(vram_w_addr),
.r_en(vram_r_en),
.w_en(vram_w_en),
.din(vram_din),
.dout(vram_dout)
);
//////////////////////////////////////////////////////////////////////////
// VGA Sync Generation
// video structure constants
parameter hpixels = 800; // horizontal pixels per line
parameter vlines = 521; // vertical lines per frame
parameter hpulse = 96; // hsync pulse length
parameter vpulse = 2; // vsync pulse length
parameter h_pixels = 799; // horizontal pixels per line
parameter v_lines = 520; // vertical lines per frame
parameter h_pulse = 96; // hsync pulse length
parameter v_pulse = 2; // vsync pulse length
parameter hbp = 144; // end of horizontal back porch
parameter hfp = 784; // beginning of horizontal front porch
parameter vbp = 31; // end of vertical back porch
parameter vfp = 511; // beginning of vertical front porch
// registers for storing the horizontal & vertical counters
reg [9:0] hc;
reg [9:0] vc;
reg [5:0] hpos;
reg [4:0] vpos;
reg [3:0] hdot;
reg [4:0] vdot;
reg [9:0] h_cnt;
reg [9:0] v_cnt;
wire [3:0] h_dot;
reg [4:0] v_dot;
reg [5:0] h_cursor;
reg [4:0] v_cursor;
wire vga_h_act;
wire vga_v_act;
wire h_active;
wire v_active;
assign h_active = (h_cnt >= hbp && h_cnt < hfp);
assign v_active = (v_cnt >= vbp && v_cnt < vfp);
assign vga_h_act = (hc >= hbp && hc < hfp);
assign vga_v_act = (vc >= vbp && vc < vfp);
assign vga_h_sync = (hc < hpulse) ? 0 : 1;
assign vga_v_sync = (vc < vpulse) ? 0 : 1;
//assign vblank = (vc >= vbp && vc < vfp) ? 0:1;
always @(posedge clk25)
begin
if (hc < hpixels - 1)
begin
hc <= hc + 1;
// count 16 pixels, so 640px / 16 = 40 characters
if (vga_h_act)
begin
hdot <= hdot + 1;
if (hdot == 4'hF)
begin
hdot <= 0;
hpos <= hpos + 1;
end
end
end
else
begin
// reset horizontal counters
hc <= 0;
hdot <= 0;
hpos <= 0;
if (vc < vlines - 1)
begin
vc <= vc + 1;
// count 20 rows, so 480px / 20 = 24 rows
if (vga_v_act)
begin
vdot <= vdot + 1;
if (vdot == 5'd19)
begin
vdot <= 0;
vpos <= vpos + 1;
end
end
end
else
begin
// reset vertical counters
vc <= 0;
vdot <= 0;
vpos <= 0;
end
end
end
reg out;
assign vga_red = out;
assign vga_grn = out;
assign vga_blu = out;
reg [8:0] cur_chr_offset;
reg [9:0] v_pos_offset;
reg [3:0] v_offset;
reg [2:0] h_offset;
reg blink;
assign vga_h_sync = (h_cnt < h_pulse) ? 0 : 1;
assign vga_v_sync = (v_cnt < v_pulse) ? 0 : 1;
always @(posedge clk25 or posedge rst)
begin
if (rst)
begin
vram_r_addr = 10'd0;
vram_r_en = 1'b0;
h_cnt <= 10'd0;
v_cnt <= 10'd0;
v_dot <= 5'd0;
end
else
begin
// get the current character from vram and build
// offset to map into character ROM (5x7 font)
if (blink && (hpos == h_cursor && vpos == v_cursor))
cur_chr_offset = 9'd0; // the @ character
if (h_cnt < h_pixels)
h_cnt <= h_cnt + 1;
else
begin
vram_r_en = 1'b1;
v_pos_offset = (vpos * 40);
vram_r_addr = (v_pos_offset + {4'b0, hpos});
cur_chr_offset = (vram_dout * 7);
// reset horizontal counters
h_cnt <= 0;
//cur_chr_offset <= (v_ram[hpos + (40 * vpos)] * 7);
end
case ({vga_h_act, vga_v_act})
default:
// outside display area
out = 1'b0;
2'b11:
begin
// we're inside the visible screen display frame
//
// scan doubling is achieved by ignoring bit 0 of both vdot
// and hdot counters, in affect doubling the pixel size
// (each pixel becomes screen pixels)
case (vdot[4:1])
4'b0000,
4'b0001,
4'b1001:
if (v_cnt < v_lines)
begin
// blank lines for spacing
out = 1'b0;
end
v_cnt <= v_cnt + 1;
default:
// count 20 rows, so 480px / 20 = 24 rows
if (v_active)
begin
v_dot <= v_dot + 1;
if (v_dot == 5'd19)
v_dot <= 0;
end
end
else
begin
// work out character rom offset for current line
// taking away 2 from counter to allow for the two
// blank preceding lines
v_offset = (vdot[4:1] - 2);
case (hdot[3:1])
3'b000,
3'b110,
3'b111:
begin
// blank columns for spacing
out = 1'b0;
end
default:
begin
// work out the character rom offset for the current
// column. We reverse the dot pattern by subtracting
// the column from the number of pixel in the
// character row in rom
h_offset = (5 - hdot[3:1]);
// grab the pixel from the character rom for
// the given screen column and line
out = c_rom[cur_chr_offset + {5'b0, v_offset}][h_offset];
end
endcase
// reset vertical counters
v_cnt <= 0;
v_dot <= 0;
end
endcase
end
endcase
end
end
reg cls_flag, cls_running;
// count 16 pixels, so 640px / 16 = 40 characters
assign h_dot = h_active ? h_cnt[3:0] : 4'd0;
//////////////////////////////////////////////////////////////////////////
// Character ROM
wire [5:0] font_char;
wire [3:0] font_pixel;
wire [4:0] font_line;
wire font_out;
font_rom my_font_rom(
.clk(clk25),
.character(font_char),
.pixel(font_pixel),
.line(font_line),
.out(font_out)
);
//////////////////////////////////////////////////////////////////////////
// Video RAM
wire [9:0] vram_r_addr;
reg [9:0] vram_w_addr;
reg vram_w_en;
reg [5:0] vram_din;
wire [5:0] vram_dout;
vram my_vram(
.clk(clk25),
.rst(rst),
.read_addr(vram_r_addr),
.write_addr(vram_w_addr),
.r_en(h_active),
.w_en(vram_w_en),
.din(vram_din),
.dout(vram_dout)
);
reg [5:0] vram_h_addr;
reg [9:0] vram_v_addr;
//////////////////////////////////////////////////////////////////////////
// Video Signal Generation
always @(posedge clk25 or posedge rst) begin
if (rst) begin
vram_h_addr <= 0;
vram_v_addr <= 0;
end else begin
// start the pipeline for reading vram and font details
// 3 pixel clock cycles early
if (h_dot == 4'hC)
vram_h_addr <= vram_h_addr + 1;
// advance to next row when last display line is reached for row
if (v_dot == 5'd19 && h_cnt == 10'd0)
vram_v_addr <= vram_v_addr + 10'h28;
// clear the address registers if we're not in visible area
if (~h_active)
vram_h_addr <= 0;
if (~v_active)
vram_v_addr <= 0;
end
end
assign vram_r_addr = ({4'd0, vram_h_addr} + vram_v_addr);
assign font_char = vram_dout;
assign font_pixel = h_dot + 1; // offset by one to get pixel into right cycle,
// font output one pixel clk behind
assign font_line = v_dot;
assign vga_red = font_out;
assign vga_grn = font_out;
assign vga_blu = font_out;
reg char_seen;
always @(posedge clk25 or posedge rst)
begin
if (rst)
begin
blink <= 1'b1;
h_cursor <= 6'd0;
v_cursor <= 5'd0;
char_seen <= 0;
debug <= 0;
cls_running <= 0;
cls_flag <= 1;
end
else
begin
if (cls_flag || clr_screen_btn)
vram_w_en <= 0;
if (address == 1'b0) // address low == TX register
begin
if ((vpos == 0) && (hpos == 0))
cls_running <= 1;
if (cls_running)
if (enable & w_en & ~char_seen)
begin
// clear the vram using the position pointers
// very similar to the original apple 1 :)
vram_w_addr <= ((vpos * 40) + {4'b0, hpos});
vram_din <= 6'd0;
vram_w_en <= 1;
// incoming character
char_seen <= 1;
if ((vpos == 23) && (hpos == 40))
case(din)
8'h8D:
begin
cls_running <= 0;
// handle carriage return
h_cursor <= 0;
v_cursor <= v_cursor + 1;
end
end
else
begin
cls_flag <= 0;
end
end
begin
vram_w_en <= 0;
if (address == 1'b0) // address low == TX register
begin
if (enable & w_en & ~char_seen)
8'h7F:
// ignore the DDR call to the PIA
h_cursor <= h_cursor + 1;
default:
begin
// incoming character
debug <= {8'd0, din};
char_seen <= 1;
case(din)
8'h8D:
begin
// handle carriage return
h_cursor <= 0;
v_cursor <= v_cursor + 1;
end
8'h7F:
// ignore the DDR call to the PIA
h_cursor <= h_cursor + 1;
default:
begin
vram_w_addr <= ((v_cursor * 40) + {4'b0, h_cursor});
vram_din <= {~din[6], din[4:0]};
vram_w_en <= 1;
h_cursor <= h_cursor + 1;
end
endcase
if (h_cursor == 39)
begin
h_cursor <= 0;
v_cursor <= v_cursor + 1;
end
if (v_cursor == 23)
begin
// here we need to add the scroll, probably by moving the
// HEAD of vram up one line
v_cursor <= 0;
end
vram_w_addr <= ((v_cursor * 40) + {4'b0, h_cursor});
vram_din <= {~din[6], din[4:0]};
vram_w_en <= 1;
h_cursor <= h_cursor + 1;
end
else if(~enable & ~w_en)
char_seen <= 0;
end
end
endcase
if (blink_clken)
blink <= ~blink;
if (h_cursor == 39)
begin
h_cursor <= 0;
v_cursor <= v_cursor + 1;
end
if (v_cursor == 23)
begin
// here we need to add the scroll, probably by moving the
// HEAD of vram up one line
v_cursor <= 0;
end
end
else if(~enable & ~w_en)
char_seen <= 0;
end
end
end
endmodule

View File

@ -24,6 +24,7 @@
module vram(
input clk, // clock signal
input rst, //
input [9:0] read_addr, // read address bus
input [9:0] write_addr, // write address bus
input r_en, // active high read enable strobe
@ -33,7 +34,7 @@ module vram(
);
`ifdef SIM
parameter RAM_FILENAME = "../roms/ram.hex";
parameter RAM_FILENAME = "../roms/vga_vram.bin";
`else
parameter RAM_FILENAME = "../../roms/vga_vram.bin";
`endif
@ -41,13 +42,19 @@ module vram(
reg [5:0] ram_data[0:1023];
initial
$readmemb(RAM_FILENAME, ram_data, 0, 1024);
$readmemb(RAM_FILENAME, ram_data, 0, 1023);
always @(posedge clk)
always @(posedge clk or posedge rst )
begin
if (r_en) dout <= ram_data[read_addr];
if (w_en) ram_data[write_addr] <= din;
if (rst)
dout <= 0;
else
begin
//if (r_en) dout <= ram_data[read_addr];
dout <= ram_data[read_addr];
if (w_en) ram_data[write_addr] <= din;
end
end
endmodule