/*
 * Copyright (c) 2014, Aleksander Osman
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package ao486.utils;

public class VGAParams {
    public static void main(String args[]) throws Exception {
        int mode_4[] = //320x200 APA
        {
            /* index=0x04 vga mode 0x04 */
            40, 24, 8, 0x00, 0x08, /* tw, th-1, ch, slength */
            0x09, 0x03, 0x00, 0x02, /* sequ_regs */
            0x63, /* miscreg */
            0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
            0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
            0xff, /* crtc_regs */
            0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
            0x01, 0x00, 0x03, 0x00, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff, /* grdc_regs */
        };
        
        int mode_6[] = //640x200 APA
        {
            /* index=0x06 vga mode 0x06 */
            80, 24, 8, 0x00, 0x10, /* tw, th-1, ch, slength */
            0x01, 0x01, 0x00, 0x06, /* sequ_regs */
            0x63, /* miscreg */
            0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
            0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2,
            0xff, /* crtc_regs */
            0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
            0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
            0x01, 0x00, 0x01, 0x00, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0f, 0xff, /* grdc_regs */
        };
        
        int mode_7[] = //720x400 A/N
        {
            /* index=0x07 vga mode 0x07 */
            80, 24, 16, 0x00, 0x10, /* tw, th-1, ch, slength */
            0x00, 0x03, 0x00, 0x02, /* sequ_regs */
            0x66, /* miscreg */
            0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
            0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
            0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
            0xff, /* crtc_regs */
            0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
            0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
            0x0e, 0x00, 0x0f, 0x08, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff, /* grdc_regs */
        };
        
        int mode_d[] = //320x200 APA
        {
            /* index=0x0d vga mode 0x0d */
            40, 24, 8, 0x00, 0x20, /* tw, th-1, ch, slength */
            0x09, 0x0f, 0x00, 0x06, /* sequ_regs */
            0x63, /* miscreg */
            0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
            0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3,
            0xff, /* crtc_regs */
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
            0x01, 0x00, 0x0f, 0x00, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
        };
        
        int mode_e[] = //640x200 APA
        {
            /* index=0x0e vga mode 0x0e */
            80, 24, 8, 0x00, 0x40, /* tw, th-1, ch, slength */
            0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
            0x63, /* miscreg */
            0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
            0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3,
            0xff, /* crtc_regs */
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
            0x01, 0x00, 0x0f, 0x00, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
        };
        
        int mode_f[] = //640x350
        {
            /* index=0x11 vga mode 0x0f */
            80, 24, 14, 0x00, 0x80, /* tw, th-1, ch, slength */
            0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
            0xa3, /* miscreg */
            0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
            0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
            0xff, /* crtc_regs */
            0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
            0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
            0x01, 0x00, 0x01, 0x00, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
        };
        
        int mode_10[] = //640x350
        {
            /* index=0x12 vga mode 0x10 */
            80, 24, 14, 0x00, 0x80, /* tw, th-1, ch, slength */
            0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
            0xa3, /* miscreg */
            0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
            0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
            0xff, /* crtc_regs */
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
            0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
            0x01, 0x00, 0x0f, 0x00, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
        };
        
        int mode_1[] = //360x400
        {
            /* index=0x17 vga mode 0x01 */
            40, 24, 16, 0x00, 0x08, /* tw, th-1, ch, slength */
            0x08, 0x03, 0x00, 0x02, /* sequ_regs */
            0x67, /* miscreg */
            0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
            0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
            0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
            0xff, /* crtc_regs */
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
            0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
            0x0c, 0x00, 0x0f, 0x08, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff, /* grdc_regs */
        };
        
        int mode_3[] = //720x400
        {
            /* index=0x18 vga mode 0x03 */
            80, 24, 16, 0x00, 0x10, /* tw, th-1, ch, slength */
            0x00, 0x03, 0x00, 0x02, /* sequ_regs */
            0x67, /* miscreg */
            0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
            0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
            0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
            0xff, /* crtc_regs */
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
            0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
            0x0c, 0x00, 0x0f, 0x08, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff, /* grdc_regs */
        };
        
        int mode_7_2[] = //720x400
        {
            /* index=0x19 vga mode 0x07 */
            80, 24, 16, 0x00, 0x10, /* tw, th-1, ch, slength */
            0x00, 0x03, 0x00, 0x02, /* sequ_regs */
            0x66, /* miscreg */
            0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
            0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
            0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
            0xff, /* crtc_regs */
            0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
            0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
            0x0e, 0x00, 0x0f, 0x08, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff, /* grdc_regs */
        };
        
        int mode_11[] = //640x480
        {
            /* index=0x1a vga mode 0x11 */
            80, 29, 16, 0x00, 0x00, /* tw, th-1, ch, slength */
            0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
            0xe3, /* miscreg */
            0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
            0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
            0xff, /* crtc_regs */
            0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
            0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
            0x01, 0x00, 0x0f, 0x00, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
        };
        
        int mode_12[] = //640x480
        {
            /* index=0x1b vga mode 0x12 */
            80, 29, 16, 0x00, 0x00, /* tw, th-1, ch, slength */
            0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
            0xe3, /* miscreg */
            0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
            0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
            0xff, /* crtc_regs */
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
            0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
            0x01, 0x00, 0x0f, 0x00, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
        };
        
        int mode_13[] = //320x200
        {
            /* index=0x1c vga mode 0x13 */
            40, 24, 8, 0x00, 0x00, /* tw, th-1, ch, slength */
            0x01, 0x0f, 0x00, 0x0e, /* sequ_regs */
            0x63, /* miscreg */
            0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
            0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
            0xff, /* crtc_regs */
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
            0x41, 0x00, 0x0f, 0x00, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff, /* grdc_regs */
        };
        
        int mode_6a[] = //800x600
        {
            /* index=0x1d vga mode 0x6a */
            100, 36, 16, 0x00, 0x00, /* tw, th-1, ch, slength */
            0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
            0xe3, /* miscreg */
            0x7f, 0x63, 0x63, 0x83, 0x6b, 0x1b, 0x72, 0xf0,
            0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x59, 0x8d, 0x57, 0x32, 0x00, 0x57, 0x73, 0xe3,
            0xff, /* crtc_regs */
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
            0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
            0x01, 0x00, 0x0f, 0x00, /* actl_regs */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
        };
        
        int vals[] = mode_1;
        
        int seq1 = vals[5];
        boolean seq_9pixel_char         = ((seq1 >> 0) & 1) == 0;
        boolean seq_dotclock_divided    = ((seq1 >> 3) & 1) == 1;
        
        int crtc0 = vals[10+0];
        int crtc1 = vals[10+1];
        int crtc2 = vals[10+2];
        int crtc3 = vals[10+3];
        int crtc4 = vals[10+4];
        int crtc5 = vals[10+5];
        int crtc6 = vals[10+6];
        int crtc7 = vals[10+7];
        int crtc9 = vals[10+9];
        int crtc16= vals[10+16];
        int crtc17= vals[10+17];
        int crtc18= vals[10+18];
        int crtc21= vals[10+21];
        int crtc22= vals[10+22];
        
        int misc  = vals[9];
        
        //---
        
        int crtc_horizontal_total = crtc0 & 0xFF;
        
        int crtc_horizontal_display_size = crtc1 & 0xFF;
        
        int crtc_horizontal_blanking_start = crtc2 & 0xFF;
        
        int crtc_horizontal_blanking_end = ((crtc5 >> 2) & 0x20) | (crtc3 & 0x1F);
        
        int horiz_blank = 1;
        while(((crtc_horizontal_blanking_start + horiz_blank) & 0x3F) != crtc_horizontal_blanking_end) horiz_blank++;
        
        int crtc_horizontal_retrace_start = (crtc4 & 0xFF) + ((crtc5 >> 5) & 3);
        
        int crtc_horizontal_retrace_end = crtc5 & 0x1F;
        
        int horiz_retrace = 1;
        while(((crtc_horizontal_retrace_start + horiz_retrace) & 0x1F) != crtc_horizontal_retrace_end) horiz_retrace++;
        
        int crtc_vertical_total = ((crtc7 << 4) & 0x200) | ((crtc7 << 8) & 0x100) | (crtc6 & 0xFF);
                
        boolean crtc_vertical_doublescan = ((crtc9 >> 7) & 1) == 1;
        
        int crtc_vertical_retrace_start = ((crtc7 << 2) & 0x200) | ((crtc7 << 6) & 0x100) | (crtc16 & 0xFF);
        
        int crtc_vertical_retrace_end = crtc17 & 0xF;
        
        int vert_retrace = 1;
        while(((crtc_vertical_retrace_start + vert_retrace) & 0xF) != crtc_vertical_retrace_end) vert_retrace++;
        
        int crtc_vertical_display_size = ((crtc7 << 3) & 0x200) | ((crtc7 << 7) & 0x100) | (crtc18 & 0xFF);
        
        int crtc_vertical_blanking_start = ((crtc9 << 4) & 0x200) | ((crtc7 << 5) & 0x100) | (crtc21 & 0xFF);
        
        int crtc_vertical_blanking_end = crtc22 & 0x7F;
        
        int vert_blank = 1;
        while(((crtc_vertical_blanking_start + vert_blank) & 0x7F) != crtc_vertical_blanking_end) vert_blank++;
        
        boolean general_vsync = ((misc >> 7) & 1) == 1;
        boolean general_hsync = ((misc >> 6) & 1) == 1;
        
        //---------------
        
        System.out.printf("wire seq_9pixel_char = 1'b%d;\n",
                seq_9pixel_char? 1 : 0);
        System.out.printf("wire seq_dotclock_divided = 1'b%d;\n",
                seq_dotclock_divided? 1 : 0);
        
        System.out.println("");
        
        System.out.printf("wire [7:0] crtc_horizontal_total          = 8'd%d; // +5 real value\n",
                crtc_horizontal_total);
        System.out.printf("wire [7:0] crtc_horizontal_display_size   = 8'd%d; // +1 for full display size\n",
                crtc_horizontal_display_size);
        System.out.printf("wire [7:0] crtc_horizontal_blanking_start = 8'd%d; // start on this character\n",
                crtc_horizontal_blanking_start);
        System.out.printf("wire [5:0] crtc_horizontal_blanking_end   = 6'd%d; // blank for %d character clocks (one side); last %d; %d first after\n",
                crtc_horizontal_blanking_end, horiz_blank, crtc_horizontal_blanking_start+horiz_blank-1, crtc_horizontal_blanking_start+horiz_blank);
        System.out.printf("wire [7:0] crtc_horizontal_retrace_start  = 8'd%d; // start on this\n",
                crtc_horizontal_retrace_start);
        System.out.printf("wire [4:0] crtc_horizontal_retrace_end    = 5'd%d;  // retrace for %d character clocks (one side); last %d; %d first after\n",
                crtc_horizontal_retrace_end, horiz_retrace, crtc_horizontal_retrace_start+horiz_retrace-1, crtc_horizontal_retrace_start+horiz_retrace);
        
        System.out.println("");
        
        System.out.printf("wire [9:0] crtc_vertical_total            = 10'd%d;\n",
                crtc_vertical_total);
        System.out.printf("wire [9:0] crtc_vertical_display_size     = 10'd%d; // 0-%d active display = %d lines\n",
                crtc_vertical_display_size,crtc_vertical_display_size,crtc_vertical_display_size+1);
        System.out.printf("wire [9:0] crtc_vertical_blanking_start   = 10'd%d; // starts on this line\n",
                crtc_vertical_blanking_start);
        System.out.printf("wire [6:0] crtc_vertical_blanking_end     = 7'd%d;  // %d lines (one side); last %d; %d first after\n",
                crtc_vertical_blanking_end,vert_blank,crtc_vertical_blanking_start+vert_blank-1,crtc_vertical_blanking_start+vert_blank);
        System.out.printf("wire [9:0] crtc_vertical_retrace_start    = 10'd%d; // starts on this line\n",
                crtc_vertical_retrace_start);
        System.out.printf("wire [3:0] crtc_vertical_retrace_end      = 4'd%d;  // %d lines (one side); last %d; %d first after\n",
                crtc_vertical_retrace_end,vert_retrace,crtc_vertical_retrace_start+vert_retrace-1,crtc_vertical_retrace_start+vert_retrace);

        System.out.println("");
        
        System.out.printf("wire       crtc_vertical_doublescan       = 1'b%d;\n", crtc_vertical_doublescan? 1 : 0);
        
        System.out.printf("wire general_vsync = 1'b%d; //pusle is ~(general_vsync)\n",
                general_vsync? 1 : 0);
        System.out.printf("wire general_hsync = 1'b%d; //pusle is ~(general_vsync)\n",
                general_hsync? 1 : 0);
    }
}
