#!/usr/bin/env python3 '''VGASimulator.py - Pedro José Pereira Vieito © 2016 View VGA output from a VHDL simulation. Ported from VGA Simulator: https://github.com/MadLittleMods/vga-simulator by Eric Eastwood More info about how to generate VGA output from VHDL simulation here: http://ericeastwood.com/blog/8/vga-simulator-getting-started Usage: VGASimulator.py [] Options: -h, --help Show this help ''' import sys import os import re import struct from PIL import Image from docopt import docopt __author__ = "Pedro José Pereira Vieito" __email__ = "pvieito@gmail.com" def time_conversion(unit_from, unit_to, value): # convert between the following: # fs, ps, ns, us, ms, sec, min, hr unit_dict = { "fs": .000000000000001, "ps": .000000000001, "ns": .000000001, "us": .000001, "ms": .001, "s": 1, "sec": 1, "min": 60, "hr": 3600, } return unit_dict[unit_from] / unit_dict[unit_to] * value def bin_to_color(binary): # Returns a value 0-255 corresponding to the bit depth # of the binary number and the value. # This is why your rgb values need to be padded to the full bit depth return int(int(binary, 2) / int("1" * len(binary), 2) * 255) def render_vga(file): vga_file = open(file, 'r') # From: http://tinyvga.com/vga-timing/ res_x = 640 res_y = 480 # Pixel Clock: ~10 ns, 108 MHz pixel_clk = 40e-9 back_porch_x = 48 #318 back_porch_y = 33 #38 h_counter = 0 v_counter = 0 back_porch_x_count = 0 back_porch_y_count = 0 last_hsync = -1 last_vsync = -1 time_last_line = 0 # Time from the last line time_last_pixel = 0 # Time since we added a pixel to the canvas frame_count = 0 vga_output = None print('[ ] VGA Simulator') print('[ ] Resolution:', res_x, '×', res_y) for vga_line in vga_file: pattern = re.compile("^([0-9]+) (fs|ps|ns|us|ms|sec|min|hr): " "(0|1) (0|1) ((?:0|1)+) ((?:0|1)+) " "((?:0|1)+)") match = pattern.match(vga_line) if (match): time = time_conversion(match.group(2), "sec", int(match.group(1))) hsync = int(match.group(3)) vsync = int(match.group(4)) red = bin_to_color(match.group(5)) green = bin_to_color(match.group(6)) blue = bin_to_color(match.group(7)) time_last_pixel += time - time_last_line if last_hsync == 0 and hsync == 1: h_counter = 0 # Move to the next row, if past back porch if back_porch_y_count >= back_porch_y: v_counter += 1 # Increment this so we know how far we are # after the vsync pulse back_porch_y_count += 1 # Set this to zero so we can count up to the actual back_porch_x_count = 0 # Sync on sync pulse time_last_pixel = 0 if last_vsync == 0 and vsync == 1: # Show frame or create new frame if vga_output: print("Showing frame") vga_output.show("VGA Output") else: print("creating frame") vga_output = Image.new('RGB', (res_x, res_y), (0, 0, 0)) if frame_count < frames_limit or frames_limit == -1: print("[+] VSYNC: Decoding frame", frame_count) frame_count += 1 h_counter = 0 v_counter = 0 # Set this to zero so we can count up to the actual back_porch_y_count = 0 # Sync on sync pulse time_last_pixel = 0 else: print("[ ]", frames_limit, "frames decoded") exit(0) if vga_output and vsync: # Add a tolerance so that the timing doesn't have to be bang on tolerance = 5e-9 if time_last_pixel >= (pixel_clk - tolerance) and \ time_last_pixel <= (pixel_clk + tolerance): # Increment this so we know how far we are # After the hsync pulse back_porch_x_count += 1 # If we are past the back porch # Then we can start drawing on the canvas if back_porch_x_count >= back_porch_x and \ back_porch_y_count >= back_porch_y: # Add pixel if h_counter < res_x and v_counter < res_y: vga_output.putpixel((h_counter, v_counter), (red, green, blue)) # Move to the next pixel, if past back porch if back_porch_x_count >= back_porch_x: h_counter += 1 # Reset time since we dealt with it time_last_pixel = 0 last_hsync = hsync last_vsync = vsync time_last_line = time vga_output.show("VGA Output") vga_output.save("out.png") args = docopt(__doc__) file = args[''] if args['']: frames_limit = int(args['']) else: frames_limit = -1 vga_extensions = ['.vga', '.txt'] if os.path.isfile(file) and os.path.splitext(file)[1] in vga_extensions: render_vga(file) print("[ ]", "Final frame decoded") else: print('[x] VGA output file (.vga) not found.')