From 20919fa7267bdcd97943c0a9264bdaa02677f4b9 Mon Sep 17 00:00:00 2001 From: Alan Garfield Date: Mon, 5 Feb 2018 00:12:06 +1100 Subject: [PATCH] wip of the pipeline VGA module. stupid yosys bug, but testbench looks ok --- iverilog/apple1_tb.v | 146 ------ iverilog/run_vga_tb.sh | 2 + iverilog/vga_files.txt | 4 + iverilog/vga_tb.v | 95 ++++ roms/vga_font.bin | 1088 +++++++++++++++++++++++----------------- roms/vga_vram.bin | 64 +++ rtl/vga/font_rom.v | 54 ++ rtl/vga/vga.v | 395 ++++++--------- rtl/vga/vram.v | 19 +- 9 files changed, 1029 insertions(+), 838 deletions(-) create mode 100755 iverilog/run_vga_tb.sh create mode 100644 iverilog/vga_files.txt create mode 100644 iverilog/vga_tb.v create mode 100644 rtl/vga/font_rom.v diff --git a/iverilog/apple1_tb.v b/iverilog/apple1_tb.v index d1d14e6..dd35131 100644 --- a/iverilog/apple1_tb.v +++ b/iverilog/apple1_tb.v @@ -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; diff --git a/iverilog/run_vga_tb.sh b/iverilog/run_vga_tb.sh new file mode 100755 index 0000000..5adf341 --- /dev/null +++ b/iverilog/run_vga_tb.sh @@ -0,0 +1,2 @@ +iverilog -DSIM -g2005 -s vga_tb -o vga_tb -c vga_files.txt +vvp vga_tb diff --git a/iverilog/vga_files.txt b/iverilog/vga_files.txt new file mode 100644 index 0000000..4a5d61a --- /dev/null +++ b/iverilog/vga_files.txt @@ -0,0 +1,4 @@ +../rtl/vga/vga.v +../rtl/vga/vram.v +../rtl/vga/font_rom.v +vga_tb.v diff --git a/iverilog/vga_tb.v b/iverilog/vga_tb.v new file mode 100644 index 0000000..6fb81bd --- /dev/null +++ b/iverilog/vga_tb.v @@ -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 diff --git a/roms/vga_font.bin b/roms/vga_font.bin index 4cf0ab5..5df4416 100644 --- a/roms/vga_font.bin +++ b/roms/vga_font.bin @@ -1,511 +1,703 @@ -01110 -10001 -10101 -10111 -10110 -10000 -01111 +00000000 +00000000 +00111000 +01000100 +01010100 +01011100 +01011000 +01000000 +00111100 +00000000 -00100 -01010 -10001 -10001 -11111 -10001 -10001 +00000000 +00000000 +00010000 +00101000 +01000100 +01000100 +01111100 +01000100 +01000100 +00000000 -11110 -10001 -10001 -11110 -10001 -10001 -11110 +00000000 +00000000 +01111000 +01000100 +01000100 +01111000 +01000100 +01000100 +01111000 +00000000 -01110 -10001 -10000 -10000 -10000 -10001 -01110 +00000000 +00000000 +00111000 +01000100 +01000000 +01000000 +01000000 +01000100 +00111000 +00000000 -11110 -10001 -10001 -10001 -10001 -10001 -11110 +00000000 +00000000 +01111000 +01000100 +01000100 +01000100 +01000100 +01000100 +01111000 +00000000 -11111 -10000 -10000 -11110 -10000 -10000 -11111 +00000000 +00000000 +01111100 +01000000 +01000000 +01111000 +01000000 +01000000 +01111100 +00000000 -11111 -10000 -10000 -11110 -10000 -10000 -10000 +00000000 +00000000 +01111100 +01000000 +01000000 +01111000 +01000000 +01000000 +01000000 +00000000 -01111 -10000 -10000 -10000 -10011 -10001 -01111 +00000000 +00000000 +00111100 +01000000 +01000000 +01000000 +01001100 +01000100 +00111100 +00000000 -10001 -10001 -10001 -11111 -10001 -10001 -10001 +00000000 +00000000 +01000100 +01000100 +01000100 +01111100 +01000100 +01000100 +01000100 +00000000 -01110 -00100 -00100 -00100 -00100 -00100 -01110 +00000000 +00000000 +00111000 +00010000 +00010000 +00010000 +00010000 +00010000 +00111000 +00000000 -00001 -00001 -00001 -00001 -00001 -10001 -01110 +00000000 +00000000 +00000100 +00000100 +00000100 +00000100 +00000100 +01000100 +00111000 +00000000 -10001 -10010 -10100 -11000 -10100 -10010 -10001 +00000000 +00000000 +01000100 +01001000 +01010000 +01100000 +01010000 +01001000 +01000100 +00000000 -10000 -10000 -10000 -10000 -10000 -10000 -11111 +00000000 +00000000 +01000000 +01000000 +01000000 +01000000 +01000000 +01000000 +01111100 +00000000 -10001 -11011 -10101 -10101 -10001 -10001 -10001 +00000000 +00000000 +01000100 +01101100 +01010100 +01010100 +01000100 +01000100 +01000100 +00000000 -10001 -10001 -11001 -10101 -10011 -10001 -10001 +00000000 +00000000 +01000100 +01000100 +01100100 +01010100 +01001100 +01000100 +01000100 +00000000 -01110 -10001 -10001 -10001 -10001 -10001 -01110 +00000000 +00000000 +00111000 +01000100 +01000100 +01000100 +01000100 +01000100 +00111000 +00000000 -11110 -10001 -10001 -11110 -10000 -10000 -10000 +00000000 +00000000 +01111000 +01000100 +01000100 +01111000 +01000000 +01000000 +01000000 +00000000 -01110 -10001 -10001 -10001 -10101 -10010 -01101 +00000000 +00000000 +00111000 +01000100 +01000100 +01000100 +01010100 +01001000 +00110100 +00000000 -11110 -10001 -10001 -11110 -10100 -10010 -10001 +00000000 +00000000 +01111000 +01000100 +01000100 +01111000 +01010000 +01001000 +01000100 +00000000 -01110 -10001 -10000 -01110 -00001 -10001 -01110 +00000000 +00000000 +00111000 +01000100 +01000000 +00111000 +00000100 +01000100 +00111000 +00000000 -11111 -00100 -00100 -00100 -00100 -00100 -00100 +00000000 +00000000 +01111100 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00000000 -10001 -10001 -10001 -10001 -10001 -10001 -01110 +00000000 +00000000 +01000100 +01000100 +01000100 +01000100 +01000100 +01000100 +00111000 +00000000 -10001 -10001 -10001 -10001 -10001 -01010 -00100 +00000000 +00000000 +01000100 +01000100 +01000100 +01000100 +01000100 +00101000 +00010000 +00000000 -10001 -10001 -10001 -10101 -10101 -11011 -10001 +00000000 +00000000 +01000100 +01000100 +01000100 +01010100 +01010100 +01101100 +01000100 +00000000 -10001 -10001 -01010 -00100 -01010 -10001 -10001 +00000000 +00000000 +01000100 +01000100 +00101000 +00010000 +00101000 +01000100 +01000100 +00000000 -10001 -10001 -01010 -00100 -00100 -00100 -00100 +00000000 +00000000 +01000100 +01000100 +00101000 +00010000 +00010000 +00010000 +00010000 +00000000 -11111 -00001 -00010 -00100 -01000 -10000 -11111 +00000000 +00000000 +01111100 +00000100 +00001000 +00010000 +00100000 +01000000 +01111100 +00000000 -11111 -11000 -11000 -11000 -11000 -11000 -11111 +00000000 +00000000 +01111100 +01100000 +01100000 +01100000 +01100000 +01100000 +01111100 +00000000 -00000 -10000 -01000 -00100 -00010 -00001 -00000 +00000000 +00000000 +00000000 +01000000 +00100000 +00010000 +00001000 +00000100 +00000000 +00000000 -11111 -00011 -00011 -00011 -00011 -00011 -11111 +00000000 +00000000 +01111100 +00001100 +00001100 +00001100 +00001100 +00001100 +01111100 +00000000 -00000 -00000 -00100 -01010 -10001 -00000 -00000 +00000000 +00000000 +00000000 +00000000 +00010000 +00101000 +01000100 +00000000 +00000000 +00000000 -00000 -00000 -00000 -00000 -00000 -00000 -11111 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +01111100 +00000000 -00000 -00000 -00000 -00000 -00000 -00000 -00000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 -00100 -00100 -00100 -00100 -00100 -00000 -00100 +00000000 +00000000 +00010000 +00010000 +00010000 +00010000 +00010000 +00000000 +00010000 +00000000 -01010 -01010 -01010 -00000 -00000 -00000 -00000 +00000000 +00000000 +00101000 +00101000 +00101000 +00000000 +00000000 +00000000 +00000000 +00000000 -01010 -01010 -11111 -01010 -11111 -01010 -01010 +00000000 +00000000 +00101000 +00101000 +01111100 +00101000 +01111100 +00101000 +00101000 +00000000 -00100 -01111 -10100 -01110 -00101 -11110 -00100 +00000000 +00000000 +00010000 +00111100 +01010000 +00111000 +00010100 +01111000 +00010000 +00000000 -11000 -11001 -00010 -00100 -01000 -10011 -00011 +00000000 +00000000 +01100000 +01100100 +00001000 +00010000 +00100000 +01001100 +00001100 +00000000 -01000 -10100 -10100 -01000 -10101 -10010 -01101 +00000000 +00000000 +00100000 +01010000 +01010000 +00100000 +01010100 +01001000 +00110100 +00000000 -00100 -00100 -00100 -00000 -00000 -00000 -00000 +00000000 +00000000 +00010000 +00010000 +00010000 +00000000 +00000000 +00000000 +00000000 +00000000 -00100 -01000 -10000 -10000 -10000 -01000 -00100 +00000000 +00000000 +00010000 +00100000 +01000000 +01000000 +01000000 +00100000 +00010000 +00000000 -00100 -00010 -00001 -00001 -00001 -00010 -00100 +00000000 +00000000 +00010000 +00001000 +00000100 +00000100 +00000100 +00001000 +00010000 +00000000 -00100 -10101 -01110 -00100 -01110 -10101 -00100 +00000000 +00000000 +00010000 +01010100 +00111000 +00010000 +00111000 +01010100 +00010000 +00000000 -00000 -00100 -00100 -11111 -00100 -00100 -00000 +00000000 +00000000 +00000000 +00010000 +00010000 +01111100 +00010000 +00010000 +00000000 +00000000 -00000 -00000 -00000 -00000 -00100 -00100 -01000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00010000 +00010000 +00100000 +00000000 -00000 -00000 -00000 -11111 -00000 -00000 -00000 +00000000 +00000000 +00000000 +00000000 +00000000 +01111100 +00000000 +00000000 +00000000 +00000000 -00000 -00000 -00000 -00000 -00000 -00000 -00100 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00010000 +00000000 -00000 -00001 -00010 -00100 -01000 -10000 -00000 +00000000 +00000000 +00000000 +00000100 +00001000 +00010000 +00100000 +01000000 +00000000 +00000000 -01110 -10001 -10011 -10101 -11001 -10001 -01110 +00000000 +00000000 +00111000 +01000100 +01001100 +01010100 +01100100 +01000100 +00111000 +00000000 -00100 -01100 -00100 -00100 -00100 -00100 -11111 +00000000 +00000000 +00010000 +00110000 +00010000 +00010000 +00010000 +00010000 +01111100 +00000000 -01110 -10001 -00001 -00110 -01000 -10000 -11111 +00000000 +00000000 +00111000 +01000100 +00000100 +00011000 +00100000 +01000000 +01111100 +00000000 -11111 -00001 -00010 -00110 -00001 -10001 -01110 +00000000 +00000000 +01111100 +00000100 +00001000 +00011000 +00000100 +01000100 +00111000 +00000000 -00010 -00110 -01010 -10010 -11111 -00010 -00010 +00000000 +00000000 +00001000 +00011000 +00101000 +01001000 +01111100 +00001000 +00001000 +00000000 -11111 -10000 -11110 -00001 -00001 -10001 -01110 +00000000 +00000000 +01111100 +01000000 +01111000 +00000100 +00000100 +01000100 +00111000 +00000000 -00111 -01000 -10000 -11110 -10001 -10001 -01110 +00000000 +00000000 +00011100 +00100000 +01000000 +01111000 +01000100 +01000100 +00111000 +00000000 -11111 -00001 -00010 -00100 -01000 -01000 -01000 +00000000 +00000000 +01111100 +00000100 +00001000 +00010000 +00100000 +00100000 +00100000 +00000000 -01110 -10001 -10001 -01110 -10001 -10001 -01110 +00000000 +00000000 +00111000 +01000100 +01000100 +00111000 +01000100 +01000100 +00111000 +00000000 -01110 -10001 -10001 -01111 -00001 -00010 -11100 +00000000 +00000000 +00111000 +01000100 +01000100 +00111100 +00000100 +00001000 +01110000 +00000000 -00000 -00000 -00100 -00000 -00100 -00000 -00000 +00000000 +00000000 +00000000 +00000000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 -00000 -00000 -00100 -00000 -00100 -00100 -01000 +00000000 +00000000 +00000000 +00000000 +00010000 +00000000 +00010000 +00010000 +00100000 +00000000 -00010 -00100 -01000 -10000 -01000 -00100 -00010 +00000000 +00000000 +00001000 +00010000 +00100000 +01000000 +00100000 +00010000 +00001000 +00000000 -00000 -00000 -11111 -00000 -11111 -00000 -00000 +00000000 +00000000 +00000000 +00000000 +01111100 +00000000 +01111100 +00000000 +00000000 +00000000 -01000 -00100 -00010 -00001 -00010 -00100 -01000 +00000000 +00000000 +00100000 +00010000 +00001000 +00000100 +00001000 +00010000 +00100000 +00000000 -01110 -10001 -00010 -00100 -00100 -00000 -00100 +00000000 +00000000 +00111000 +01000100 +00001000 +00010000 +00010000 +00000000 +00010000 +00000000 diff --git a/roms/vga_vram.bin b/roms/vga_vram.bin index 33938ec..9b22fab 100644 --- a/roms/vga_vram.bin +++ b/roms/vga_vram.bin @@ -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 diff --git a/rtl/vga/font_rom.v b/rtl/vga/font_rom.v new file mode 100644 index 0000000..1259c36 --- /dev/null +++ b/rtl/vga/font_rom.v @@ -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 + diff --git a/rtl/vga/vga.v b/rtl/vga/vga.v index b0ae63b..992ec7d 100644 --- a/rtl/vga/vga.v +++ b/rtl/vga/vga.v @@ -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 diff --git a/rtl/vga/vram.v b/rtl/vga/vram.v index 1190384..ab653e8 100644 --- a/rtl/vga/vram.v +++ b/rtl/vga/vram.v @@ -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 - +