diff --git a/MacPlus.qsf b/MacPlus.qsf index 56d2347..51a4294 100644 --- a/MacPlus.qsf +++ b/MacPlus.qsf @@ -50,6 +50,29 @@ set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON set_global_assignment -name ALM_REGISTER_PACKING_EFFORT LOW set_global_assignment -name SEED 1 +#set_global_assignment -name VERILOG_MACRO "MISTER_FB=1" + +#enable it only if 8bit indexed mode is used in core +#set_global_assignment -name VERILOG_MACRO "MISTER_FB_PALETTE=1" + +#do not enable DEBUG_NOHDMI in release! +#set_global_assignment -name VERILOG_MACRO "MISTER_DEBUG_NOHDMI=1" + +# disable bilinear filtering when downscaling +#set_global_assignment -name VERILOG_MACRO "MISTER_DOWNSCALE_NN=1" + +# disable adaptive scanline filtering +#set_global_assignment -name VERILOG_MACRO "MISTER_DISABLE_ADAPTIVE=1" + +#use only 1MB per frame for scaler to free ~21MB DDR3 RAM +#set_global_assignment -name VERILOG_MACRO "MISTER_SMALL_VBUF=1" + +# Disable YC / Composite output to save some resources +#set_global_assignment -name VERILOG_MACRO "MISTER_DISABLE_YC=1" + +# Disable ALSA audio output to save some resources +#set_global_assignment -name VERILOG_MACRO "MISTER_DISABLE_ALSA=1" + source sys/sys.tcl source sys/sys_analog.tcl source files.qip diff --git a/MacPlus.sv b/MacPlus.sv index 8b6e9ac..60521b9 100644 --- a/MacPlus.sv +++ b/MacPlus.sv @@ -52,7 +52,7 @@ module emu output VGA_F1, output [1:0] VGA_SL, output VGA_SCALER, // Force VGA scaler - output VGA_DISABLE, // analog out is off + output VGA_DISABLE, // analog out is off input [11:0] HDMI_WIDTH, input [11:0] HDMI_HEIGHT, @@ -173,8 +173,8 @@ module emu input OSD_STATUS ); - -assign ADC_BUS = 'Z; + +assign ADC_BUS = 'Z; assign USER_OUT = '1; assign {DDRAM_CLK, DDRAM_BURSTCNT, DDRAM_ADDR, DDRAM_DIN, DDRAM_BE, DDRAM_RD, DDRAM_WE} = 0; @@ -195,8 +195,8 @@ video_freak video_freak .VGA_DE_IN(VGA_DE), .VGA_DE(), - .ARX((!ar) ? 12'd4 : (ar - 1'd1)), - .ARY((!ar) ? 12'd3 : 12'd0), + .ARX((!ar) ? 12'd256 : (ar - 1'd1)), + .ARY((!ar) ? 12'd171 : 12'd0), .CROP_SIZE(0), .CROP_OFF(0), .SCALE(status[12:11]) @@ -223,6 +223,9 @@ localparam CONF_STR = { //"OA,Serial,Off,On;", //"-;", "R0,Reset & Apply CPU+Memory;", + "v,0;", // [optional] config version 0-99. + // If CONF_STR options are changed in incompatible way, then change version number too, + // so all options will get default values on first start. "V,v",`BUILD_DATE }; diff --git a/readme.md b/readme.md index 1661ef3..8c263e9 100644 --- a/readme.md +++ b/readme.md @@ -2,50 +2,52 @@ This is a port of the [Plus Too core](https://github.com/mist-devel/mist-binaries/tree/master/cores/plus_too) from MiST which is the port of the [Plus Too project](http://www.bigmessowires.com/plus-too/). -I've tried to optimize the code with converting to synchronous style and fixing some glitches and instabilities. - +I've tried to optimize the code by converting to synchronous style and fixing some glitches and instabilities. ## Usage * Copy the [*.rbf](https://github.com/MiSTer-devel/MacPlus_MiSTer/tree/master/releases) onto the root of SD card -* Copy the [boot.rom](https://github.com/MiSTer-devel/MacPlus_MiSTer/tree/master/releases) to MacPlus folder +* Copy [boot0.rom & boot1.rom](https://github.com/MiSTer-devel/MacPlus_MiSTer/tree/master/releases) (Plus and SE ROM files) to MacPlus folder * Copy disk images in dsk format (e.g. Disk605.dsk) to MacPlus folder -After a few seconds the floppy disk icon should -appear. Open the on screen display using the F12 key and select the -a disk image. The upload of the disk image will take a few seconds. MacPlus will then boot into the MacOS desktop. +After a few seconds, the floppy disk icon should appear. Open the on-screen display using the F12 key and select the a disk image. The upload of the disk image will take a few seconds. If a bootable system is found on disk, a smiling Mac icon will appear. MacPlus will then begin booting into the desktop. -## Floppy disk image format +## Floppy disk support -Floppy disk images need to be in raw disk format. Double sided 800k disk images have to be exactly 819200 bytes in size. Single sided 400k disk images have to be exactly 409600 bytes in size. +Internal and external floppy disk drives are both supported. The first and second entries in the OSD correspond to the internal and external floppy disk drives, respectively. -Both the internal as well as the external floppy disk are supported. The first entry in the OSD refers to the internal floppy disk, the second one to the external floppy disk. +Floppy disk images need to be in raw disk format (a.k.a. DiskDup format) with a .dsk extension. Single-sided 400k disk images must be exactly 409,600 bytes in size. Double-sided 800k disk images must be exactly 819,200 bytes in size. Disk Copy 4.2 files are not currently supported. They are largely the same as raw disk format, but include an additional 84-byte header. A tool to convert DC42 format to dsk is available [here](https://www.bigmessowires.com/2013/12/16/macintosh-diskcopy-4-2-floppy-image-converter/). -Currently floppy disk images cannot be loaded while the Mac accesses a floppy disk. Thus it's recommended to wait for the desktop to appear until a second floppy can be inserted. +Currently, floppy disk images are not writable within the core. -Before loading a different disk image it's recommended to eject the previously inserted disk image from within MacOS. +Floppy disk images cannot be loaded while the Mac accesses a floppy disk. Thus, it's recommended to wait for the desktop to appear until a second floppy can be inserted. Before loading a different disk image, it's recommended to eject the previously inserted disk image from within the OS. -Official system disk images are available from apple at [here](https://web.archive.org/web/20141025043714/http://www.info.apple.com/support/oldersoftwarelist.html). Under Linux these can be converted into the desired dsk format using [Linux stuffit](http://web.archive.org/web/20060205025441/http://www.stuffit.com/downloads/files/stuffit520.611linux-i386.tar.gz), unar and [dc2dsk](http://www.bigmessowires.com/dc2dsk.c) in that order. A shell script has been provided for convenience at [releases/bin2dsk.sh](releases/bin2dsk.sh). +Note that the floppy disk drive will not be read when the CPU speed is set to 16 MHz. + +Official system disk images are available from an archived Apple support page [here](https://web.archive.org/web/20141025043714/http://www.info.apple.com/support/oldersoftwarelist.html). Under Linux these can be converted into the desired dsk format using [Linux StuffIt](http://web.archive.org/web/20060205025441/http://www.stuffit.com/downloads/files/stuffit520.611linux-i386.tar.gz), unar, and [dc2dsk](http://www.bigmessowires.com/dc2dsk.c), in that order. A shell script has been provided for convenience at [releases/bin2dsk.sh](releases/bin2dsk.sh). ## Hard disk support -This MacPlus core implements the SCSI interface of the Macintosh Plus together with a 20MB harddisk. The core implements only a subset of the SCSI commands. This is currently sufficient to read and write the disk, to boot from it and to format it using the setup tools that come with MacOS 6.0.8. +The MacPlus core supports SCSI hard drive images up to 2GB (HFS) in size, with a .vhd extension. The core currently implements only a subset of the SCSI commands. This is sufficient to read and write the disk, to boot from it, and to format it using the setup tools that come with System 6.0.8. -The harddisk image to be used can be selected from the "Mount *.vhd" entry in the on-screen-display. Copy the boot.vhd to MacPlus folder and it will be automatically mounted at start. The format of the disk image is the same as being used by the SCSI2SD project which is documented [here](http://www.codesrc.com/mediawiki/index.php?title=HFSFromScratch). +The harddisk image to be used can be selected from the "Mount *.vhd" entry in the on-screen-display. Copy the boot.vhd to MacPlus folder and it will be automatically mounted at start. The format of the disk image is the same as the one used by the SCSI2SD project, documented [here](http://www.codesrc.com/mediawiki/index.php?title=HFSFromScratch). -Unlike the floppy the SCSI disk is writable and data can be written to the disk from within the core. +Unlike the floppy, the SCSI disk is writable and data can be written to the disk from within the core. -It has been tested that OS 6.0.8 can format the SCSI disk as well as doing a full installation from floppy disk to the harddisk. But keep in mind that this is an early work in progress and expect data loss when working with HDD images. +It has been tested that System 6.0.8 can format the SCSI disk, as well as doing a full installation from floppy disk to the harddisk. However, keep in mind the core is an early work in progress and expect data loss when working with HDD images. -A matching harddisk image file can be found [here](https://github.com/MiSTer-devel/MacPlus_MiSTer/tree/master/releases). This is a 20MB harddisk image with correct partitioning information and a basic SCSI driver installed. The data partition itself is empty and unformatted. After booting the Mac will thus ask whether the disk is to be initialized. Saying yes and giving the disk a name will result im a usable file system. You don't need to use the Setup tool to format this disk as it is already formatted. But you can format it if you want to. This is only been tested with OS 6.0.8. +A matching harddisk image file can be found [here](https://github.com/MiSTer-devel/MacPlus_MiSTer/tree/master/releases). This is a 20MB harddisk image with correct partitioning information and a basic SCSI driver installed. The data partition itself is empty and unformatted. After booting the Mac will thus ask whether the disk is to be initialized. Saying yes and giving the disk a name will result in a usable file system. You don't need to use the Setup tool to format this disk as it is already formatted, but you can format it if you want to. This has only been tested with System 6.0.8. + +A tool to create harddisk images (with working SCSI driver and partition table) is available [here](https://diskjockey.onegeekarmy.eu/). ## CPU Speed -The CPU speed can be adjusted from "normal" which is roughly Mac Plus speed to "Fast" which is about 2.5 times faster. Original core couldn't boot from SCSI in turbo mode. This port has workaround to let it boot even with turbo mode. +The CPU speed can be adjusted to 8 MHz (original speed) or 16 MHz. This port implements a workaround to allow booting from SCSI when using the 16 MHz configuration. ## Memory -512KB, 1MB and 4MB memory configs are available. Cold boot with 4MB RAM selected takes some time before it start to boot from FDD/SCSI, so be patient. Warm boot won't take long time. +1MB and 4MB memory configurations are available. Cold boot with 4MB RAM selected takes some time before it starts to boot from FDD/SCSI, so be patient. Warm boot won't take as long. ## Keyboard -The Alt key is mapped to the Mac's command key, and the Windows key is mapped to the Mac's option key. Core emulates keyboard with keypad. + +The Alt key is mapped to the Mac's Command (⌘) key, and the Windows key is mapped to the Mac's Option (⌥) key. Core emulates keyboard with numeric keypad. diff --git a/sys/hps_io.sv b/sys/hps_io.sv index bf61f35..45510a9 100644 --- a/sys/hps_io.sv +++ b/sys/hps_io.sv @@ -226,7 +226,7 @@ video_calc video_calc .new_vmode(new_vmode), .video_rotated(video_rotated), - .par_num(byte_cnt[3:0]), + .par_num(byte_cnt[4:0]), .dout(vc_dout) ); @@ -502,7 +502,7 @@ always@(posedge clk_sys) begin : uio_block 'h22: RTC[(byte_cnt-6'd1)<<4 +:16] <= io_din; //Video res. - 'h23: if(!byte_cnt[MAX_W:4]) io_dout <= vc_dout; + 'h23: if(!byte_cnt[MAX_W:5]) io_dout <= vc_dout; //RTC 'h24: TIMESTAMP[(byte_cnt-6'd1)<<4 +:16] <= io_din; @@ -872,7 +872,7 @@ module video_calc input new_vmode, input video_rotated, - input [3:0] par_num, + input [4:0] par_num, output reg [15:0] dout ); @@ -893,6 +893,9 @@ always @(posedge clk_sys) begin 13: dout <= vid_vtime_hdmi[31:16]; 14: dout <= vid_ccnt[15:0]; 15: dout <= vid_ccnt[31:16]; + 16: dout <= vid_pixrep; + 17: dout <= vid_de_h; + 18: dout <= vid_de_v; default dout <= 0; endcase end @@ -902,24 +905,44 @@ reg [31:0] vid_vcnt = 0; reg [31:0] vid_ccnt = 0; reg [7:0] vid_nres = 0; reg [1:0] vid_int = 0; +reg [7:0] vid_pixrep; +reg [15:0] vid_de_h; +reg [7:0] vid_de_v; always @(posedge clk_vid) begin integer hcnt; integer vcnt; integer ccnt; - reg old_vs= 0, old_de = 0, old_vmode = 0; + reg [7:0] pcnt; + reg [7:0] de_v; + reg [15:0] de_h; + reg old_vs = 0, old_hs = 0, old_hs_vclk = 0, old_de = 0, old_de_vclk = 0, old_de1 = 0, old_vmode = 0; reg [3:0] resto = 0; reg calch = 0; if(calch & de) ccnt <= ccnt + 1; + pcnt <= pcnt + 1'd1; + + old_hs_vclk <= hs; + de_h <= de_h + 1'd1; + if(old_hs_vclk & ~hs) de_h <= 1; + + old_de_vclk <= de; + if(calch & ~old_de_vclk & de) vid_de_h <= de_h; if(ce_pix) begin old_vs <= vs; + old_hs <= hs; old_de <= de; + old_de1 <= old_de; + pcnt <= 1; if(~vs & ~old_de & de) vcnt <= vcnt + 1; if(calch & de) hcnt <= hcnt + 1; if(old_de & ~de) calch <= 0; + if(~old_de1 & old_de) vid_pixrep <= pcnt; + if(old_hs & ~hs) de_v <= de_v + 1'd1; + if(calch & ~old_de & de) vid_de_v <= de_v; if(old_vs & ~vs) begin vid_int <= {vid_int[0],f1}; @@ -939,6 +962,7 @@ always @(posedge clk_vid) begin hcnt <= 0; ccnt <= 0; calch <= 1; + de_v <= 0; end end end diff --git a/sys/mcp23009.sv b/sys/mcp23009.sv index 40cbf5e..82eaf37 100644 --- a/sys/mcp23009.sv +++ b/sys/mcp23009.sv @@ -8,10 +8,12 @@ module mcp23009 output reg [2:0] btn, input [2:0] led, - output reg sd_cd, + output reg flg_sd_cd, + output reg flg_present, + output reg flg_mode, - output scl, - inout sda + output scl, + inout sda ); @@ -50,7 +52,9 @@ always@(posedge clk) begin idx <= 0; btn <= 0; rw <= 0; - sd_cd <= 1; + flg_sd_cd <= 1; + flg_present <= 0; + flg_mode <= 1; end else begin if(~&init_data[idx]) begin @@ -84,7 +88,10 @@ always@(posedge clk) begin state <= 0; rw <= 0; if(!error) begin - if(rw) {sd_cd, btn} <= {dout[7], dout[5:3]}; + if(rw) begin + {flg_sd_cd, flg_mode, btn} <= {dout[7:3]}; + flg_present <= 1; + end rw <= ~rw; end end diff --git a/sys/pll_cfg.qip b/sys/pll_cfg.qip index c3394be..0b560f9 100644 --- a/sys/pll_cfg.qip +++ b/sys/pll_cfg.qip @@ -1,44 +1,5 @@ -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_TOOL_NAME "altera_pll_reconfig" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_TOOL_VERSION "17.0" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_TOOL_ENV "mwpim" -set_global_assignment -library "pll_cfg" -name MISC_FILE [file join $::quartus(qip_path) "pll_cfg.cmp"] -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_TARGETED_DEVICE_FAMILY "Cyclone V" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_GENERATED_DEVICE_FAMILY "{Cyclone V}" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_QSYS_MODE "UNKNOWN" set_global_assignment -name SYNTHESIS_ONLY_QIP ON -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_NAME "cGxsX2hkbWlfY2Zn" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTCBSZWNvbmZpZw==" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_REPORT_HIERARCHY "Off" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_INTERNAL "Off" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_VERSION "MTcuMA==" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIFJlY29uZmlndXJhdGlvbiBCbG9jayhBTFRFUkFfUExMX1JFQ09ORklHKQ==" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "RU5BQkxFX0JZVEVFTkFCTEU=::ZmFsc2U=::QWRkIGJ5dGVlbmFibGUgcG9ydA==" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "QllURUVOQUJMRV9XSURUSA==::NA==::QllURUVOQUJMRV9XSURUSA==" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfQUREUl9XSURUSA==::Ng==::UkVDT05GSUdfQUREUl9XSURUSA==" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfREFUQV9XSURUSA==::MzI=::UkVDT05GSUdfREFUQV9XSURUSA==" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "cmVjb25mX3dpZHRo::NjQ=::cmVjb25mX3dpZHRo" -set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "V0FJVF9GT1JfTE9DSw==::dHJ1ZQ==::V0FJVF9GT1JfTE9DSw==" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_NAME "YWx0ZXJhX3BsbF9yZWNvbmZpZ190b3A=" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTCBSZWNvbmZpZw==" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_REPORT_HIERARCHY "Off" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_INTERNAL "Off" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_VERSION "MTcuMA==" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIFJlY29uZmlndXJhdGlvbiBCbG9jayhBTFRFUkFfUExMX1JFQ09ORklHKQ==" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "ZGV2aWNlX2ZhbWlseQ==::Q3ljbG9uZSBW::ZGV2aWNlX2ZhbWlseQ==" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "RU5BQkxFX01JRg==::ZmFsc2U=::RW5hYmxlIE1JRiBTdHJlYW1pbmc=" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "RU5BQkxFX0JZVEVFTkFCTEU=::ZmFsc2U=::QWRkIGJ5dGVlbmFibGUgcG9ydA==" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "QllURUVOQUJMRV9XSURUSA==::NA==::QllURUVOQUJMRV9XSURUSA==" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfQUREUl9XSURUSA==::Ng==::UkVDT05GSUdfQUREUl9XSURUSA==" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfREFUQV9XSURUSA==::MzI=::UkVDT05GSUdfREFUQV9XSURUSA==" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "cmVjb25mX3dpZHRo::NjQ=::cmVjb25mX3dpZHRo" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "V0FJVF9GT1JfTE9DSw==::dHJ1ZQ==::V0FJVF9GT1JfTE9DSw==" - -set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg.v"] +set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg/pll_cfg.v"] +set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg/pll_cfg_hdmi.v"] set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg/altera_pll_reconfig_top.v"] set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg/altera_pll_reconfig_core.v"] - -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_TOOL_NAME "altera_pll_reconfig" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_TOOL_VERSION "17.0" -set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_TOOL_ENV "mwpim" diff --git a/sys/pll_cfg/altera_pll_reconfig_core.v b/sys/pll_cfg/altera_pll_reconfig_core.v index 4bc1fbb..a9e2b8c 100644 --- a/sys/pll_cfg/altera_pll_reconfig_core.v +++ b/sys/pll_cfg/altera_pll_reconfig_core.v @@ -16,7 +16,7 @@ module altera_pll_reconfig_core #( parameter reconf_width = 64, - parameter device_family = "Stratix V", + parameter device_family = "Cyclone V", // MIF Streaming parameters parameter RECONFIG_ADDR_WIDTH = 6, parameter RECONFIG_DATA_WIDTH = 32, @@ -1883,7 +1883,7 @@ module fpll_dprio_init ( endmodule module dyn_phase_shift #( - parameter device_family = "Stratix V" + parameter device_family = "Cyclone V" ) ( input wire clk, @@ -2112,7 +2112,7 @@ endmodule module generic_lcell_comb #( //parameter - parameter family = "Stratix V", + parameter family = "Cyclone V", parameter lut_mask = 64'hAAAAAAAAAAAAAAAA, parameter dont_touch = "on" ) ( diff --git a/sys/pll_cfg/altera_pll_reconfig_top.v b/sys/pll_cfg/altera_pll_reconfig_top.v index c1bfa8b..843c970 100644 --- a/sys/pll_cfg/altera_pll_reconfig_top.v +++ b/sys/pll_cfg/altera_pll_reconfig_top.v @@ -16,7 +16,7 @@ module altera_pll_reconfig_top #( parameter reconf_width = 64, - parameter device_family = "Stratix V", + parameter device_family = "Cyclone V", parameter RECONFIG_ADDR_WIDTH = 6, parameter RECONFIG_DATA_WIDTH = 32, diff --git a/sys/pll_cfg/pll_cfg.v b/sys/pll_cfg/pll_cfg.v new file mode 100644 index 0000000..0adc36f --- /dev/null +++ b/sys/pll_cfg/pll_cfg.v @@ -0,0 +1,86 @@ +// megafunction wizard: %Altera PLL Reconfig v17.0% +// GENERATION: XML +// pll_cfg.v + +// Generated using ACDS version 17.0 598 + +`timescale 1 ps / 1 ps +module pll_cfg #( + parameter ENABLE_BYTEENABLE = 0, + parameter BYTEENABLE_WIDTH = 4, + parameter RECONFIG_ADDR_WIDTH = 6, + parameter RECONFIG_DATA_WIDTH = 32, + parameter reconf_width = 64, + parameter WAIT_FOR_LOCK = 1 + ) ( + input wire mgmt_clk, // mgmt_clk.clk + input wire mgmt_reset, // mgmt_reset.reset + output wire mgmt_waitrequest, // mgmt_avalon_slave.waitrequest + input wire mgmt_read, // .read + input wire mgmt_write, // .write + output wire [31:0] mgmt_readdata, // .readdata + input wire [5:0] mgmt_address, // .address + input wire [31:0] mgmt_writedata, // .writedata + output wire [63:0] reconfig_to_pll, // reconfig_to_pll.reconfig_to_pll + input wire [63:0] reconfig_from_pll // reconfig_from_pll.reconfig_from_pll + ); + + altera_pll_reconfig_top #( + .device_family ("Cyclone V"), + .ENABLE_MIF (0), + .MIF_FILE_NAME ("sys/pll_cfg.mif"), + .ENABLE_BYTEENABLE (ENABLE_BYTEENABLE), + .BYTEENABLE_WIDTH (BYTEENABLE_WIDTH), + .RECONFIG_ADDR_WIDTH (RECONFIG_ADDR_WIDTH), + .RECONFIG_DATA_WIDTH (RECONFIG_DATA_WIDTH), + .reconf_width (reconf_width), + .WAIT_FOR_LOCK (WAIT_FOR_LOCK) + ) pll_cfg_inst ( + .mgmt_clk (mgmt_clk), // mgmt_clk.clk + .mgmt_reset (mgmt_reset), // mgmt_reset.reset + .mgmt_waitrequest (mgmt_waitrequest), // mgmt_avalon_slave.waitrequest + .mgmt_read (mgmt_read), // .read + .mgmt_write (mgmt_write), // .write + .mgmt_readdata (mgmt_readdata), // .readdata + .mgmt_address (mgmt_address), // .address + .mgmt_writedata (mgmt_writedata), // .writedata + .reconfig_to_pll (reconfig_to_pll), // reconfig_to_pll.reconfig_to_pll + .reconfig_from_pll (reconfig_from_pll), // reconfig_from_pll.reconfig_from_pll + .mgmt_byteenable (4'b0000) // (terminated) + ); + +endmodule +// Retrieval info: +// +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// IPFS_FILES : pll_cfg.vo +// RELATED_FILES: pll_cfg.v, altera_pll_reconfig_top.v, altera_pll_reconfig_core.v, altera_std_synchronizer.v diff --git a/sys/pll_cfg/pll_cfg_hdmi.v b/sys/pll_cfg/pll_cfg_hdmi.v new file mode 100644 index 0000000..1912c2a --- /dev/null +++ b/sys/pll_cfg/pll_cfg_hdmi.v @@ -0,0 +1,1282 @@ +// (C) 2001-2017 Intel Corporation. All rights reserved. +// Your use of Intel Corporation's design tools, logic functions and other +// software and tools, and its AMPP partner logic functions, and any output +// files any of the foregoing (including device programming or simulation +// files), and any associated documentation or information are expressly subject +// to the terms and conditions of the Intel Program License Subscription +// Agreement, Intel MegaCore Function License Agreement, or other applicable +// license agreement, including, without limitation, that your use is for the +// sole purpose of programming logic devices manufactured by Intel and sold by +// Intel or its authorized distributors. Please refer to the applicable +// agreement for further details. + +// original file was altera_pll_reconfig_core.v +// not needed functionality was cut out to reduce ressource consumption + +module pll_cfg_hdmi +#( + parameter reconf_width = 64, + parameter device_family = "Cyclone V" +) ( + + //input + input wire mgmt_clk, + input wire mgmt_reset, + + + //conduits + output wire [reconf_width-1:0] reconfig_to_pll, + input wire [reconf_width-1:0] reconfig_from_pll, + + // user data (avalon-MM slave interface) + output wire mgmt_waitrequest, + input wire [5:0] mgmt_address, + input wire mgmt_write, + input wire [31:0] mgmt_writedata +); + localparam mode_WR = 1'b0; + localparam MODE_REG = 6'b000000; + localparam START_REG = 6'b000010; + localparam N_REG = 6'b000011; + localparam M_REG = 6'b000100; + localparam C_COUNTERS_REG = 6'b000101; + //localparam DPS_REG = 6'b000110; // unused + localparam DSM_REG = 6'b000111; + localparam BWCTRL_REG = 6'b001000; + localparam CP_CURRENT_REG = 6'b001001; + //localparam ANY_DPRIO = 6'b100000; // unused + //localparam CNT_BASE = 5'b001010; // unused + //localparam VCO_REG = 6'b011100; // unused + + //C Counters + localparam number_of_counters = 5'd6; + //C counter addresses + localparam C_CNT_0_DIV_ADDR = 5'h00; + localparam C_CNT_0_DIV_ADDR_DPRIO_1 = 5'h11; + localparam C_CNT_0_3_BYPASS_EN_ADDR = 5'h15; + localparam C_CNT_0_3_ODD_DIV_EN_ADDR = 5'h17; + localparam C_CNT_4_17_BYPASS_EN_ADDR = 5'h14; + localparam C_CNT_4_17_ODD_DIV_EN_ADDR = 5'h16; + //N counter addresses + localparam N_CNT_DIV_ADDR = 5'h13; + localparam N_CNT_BYPASS_EN_ADDR = 5'h15; + localparam N_CNT_ODD_DIV_EN_ADDR = 5'h17; + //M counter addresses + localparam M_CNT_DIV_ADDR = 5'h12; + localparam M_CNT_BYPASS_EN_ADDR = 5'h15; + localparam M_CNT_ODD_DIV_EN_ADDR = 5'h17; + + //DSM address + localparam DSM_K_FRACTIONAL_DIVISION_ADDR_0 = 5'h18; + localparam DSM_K_FRACTIONAL_DIVISION_ADDR_1 = 5'h19; + localparam DSM_K_READY_ADDR = 5'h17; + localparam DSM_K_DITHER_ADDR = 5'h17; + localparam DSM_OUT_SEL_ADDR = 6'h30; + + //Other DSM params + localparam DSM_K_READY_BIT_INDEX = 4'd11; + //BWCTRL address + //Bit 0-3 of addr + localparam BWCTRL_ADDR = 6'h30; + //CP_CURRENT address + //Bit 0-2 of addr + localparam CP_CURRENT_ADDR = 6'h31; + + // VCODIV address + localparam VCO_ADDR = 5'h17; + + localparam DPRIO_IDLE = 3'd0, ONE = 3'd1, TWO = 3'd2, THREE = 3'd3, FOUR = 3'd4, + FIVE = 3'd5, SIX = 3'd6, SEVEN = 3'd7, EIGHT = 4'd8, NINE = 4'd9, TEN = 4'd10, + ELEVEN = 4'd11, TWELVE = 4'd12, THIRTEEN = 4'd13, FOURTEEN = 4'd14, DPRIO_DONE = 4'd15; + localparam IDLE = 2'b00, WAIT_ON_LOCK = 2'b01, LOCKED = 2'b10; + + wire clk; + wire reset; + wire gnd; + + wire [5: 0] slave_address; + wire slave_write; + wire [31: 0] slave_writedata; + + wire slave_waitrequest; + reg slave_mode; + + assign clk = mgmt_clk; + + assign slave_address = mgmt_address; + assign slave_write = mgmt_write; + assign slave_writedata = mgmt_writedata; + + // Outputs + assign mgmt_waitrequest = slave_waitrequest; //Read waitrequest asserted in polling mode + + //internal signals + wire locked_orig; + wire locked; + + wire pll_start; + wire pll_start_valid; + + wire pll_start_asserted; + + reg [1:0] current_state; + reg [1:0] next_state; + + reg status;//0=busy, 1=ready + //user_mode_init user_mode_init_inst (clk, reset, dprio_mdio_dis, ser_shift_load); + //declaring the init wires. These will have 0 on them for 64 clk cycles + wire [ 5:0] init_dprio_address; + wire init_dprio_read; + wire [ 1:0] init_dprio_byteen; + wire init_dprio_write; + wire [15:0] init_dprio_writedata; + + wire init_atpgmode; + wire init_mdio_dis; + wire init_scanen; + wire init_ser_shift_load; + wire dprio_init_done; + + //DPRIO output signals after initialization is done + wire dprio_clk; + reg avmm_dprio_write; + reg avmm_dprio_read; + reg [5:0] avmm_dprio_address; + reg [15:0] avmm_dprio_writedata; + reg [1:0] avmm_dprio_byteen; + wire avmm_atpgmode; + wire avmm_mdio_dis; + wire avmm_scanen; + + //Final output wires that are muxed between the init and avmm wires. + wire dprio_init_reset; + wire [5:0] dprio_address /*synthesis keep*/; + wire dprio_read/*synthesis keep*/; + wire [1:0] dprio_byteen/*synthesis keep*/; + wire dprio_write/*synthesis keep*/; + wire [15:0] dprio_writedata/*synthesis keep*/; + wire dprio_mdio_dis/*synthesis keep*/; + wire dprio_ser_shift_load/*synthesis keep*/; + wire dprio_atpgmode/*synthesis keep*/; + wire dprio_scanen/*synthesis keep*/; + + + //other PLL signals for dyn ph shift + wire phase_done/*synthesis keep*/; + wire phase_en/*synthesis keep*/; + wire up_dn/*synthesis keep*/; + wire [4:0] cnt_sel; + + //DPRIO input signals + wire [15:0] dprio_readdata; + + //internal logic signals + //storage registers for user sent data + reg dprio_temp_read_1; + reg dprio_temp_read_2; + reg dprio_start; + wire usr_valid_changes; + reg [3:0] dprio_cur_state; + reg [3:0] dprio_next_state; + reg [15:0] dprio_temp_m_n_c_readdata_1_d; + reg [15:0] dprio_temp_m_n_c_readdata_2_d; + reg [15:0] dprio_temp_m_n_c_readdata_1_q; + reg [15:0] dprio_temp_m_n_c_readdata_2_q; + reg dprio_write_done; + //C counters signals + reg [7:0] usr_c_cnt_lo; + reg [7:0] usr_c_cnt_hi; + reg usr_c_cnt_bypass_en; + reg usr_c_cnt_odd_duty_div_en; + reg temp_c_cnt_bypass_en [0:17]; + reg temp_c_cnt_odd_duty_div_en [0:17]; + reg any_c_cnt_changed; + reg all_c_cnt_done_q; + reg all_c_cnt_done_d; + reg [17:0] c_cnt_changed; + reg [17:0] c_cnt_done_d; + reg [17:0] c_cnt_done_q; + //N counter signals + reg [7:0] usr_n_cnt_lo; + reg [7:0] usr_n_cnt_hi; + reg usr_n_cnt_bypass_en; + reg usr_n_cnt_odd_duty_div_en; + reg n_cnt_changed; + reg n_cnt_done_d; + reg n_cnt_done_q; + //M counter signals + reg [7:0] usr_m_cnt_lo; + reg [7:0] usr_m_cnt_hi; + reg usr_m_cnt_bypass_en; + reg usr_m_cnt_odd_duty_div_en; + reg m_cnt_changed; + reg m_cnt_done_d; + reg m_cnt_done_q; + //dyn phase regs + reg [15:0] usr_num_shifts; + reg [4:0] usr_cnt_sel /*synthesis preserve*/; + reg usr_up_dn; + reg dps_changed; + wire dps_changed_valid; + wire dps_done; + + //DSM Signals + reg [31:0] usr_k_value; + reg dsm_k_changed; + reg dsm_k_done_d; + reg dsm_k_done_q; + reg dsm_k_ready_false_done_d; + //BW signals + reg [3:0] usr_bwctrl_value; + reg bwctrl_changed; + reg bwctrl_done_d; + reg bwctrl_done_q; + //CP signals + reg [2:0] usr_cp_current_value; + reg cp_current_changed; + reg cp_current_done_d; + reg cp_current_done_q; + //VCO signals + reg usr_vco_value; + reg vco_changed; + reg vco_done_d; + reg vco_done_q; + //Manual DPRIO signals + reg manual_dprio_done_q; + reg manual_dprio_done_d; + reg manual_dprio_changed; + reg [5:0] usr_dprio_address; + reg [15:0] usr_dprio_writedata_0; + reg usr_r_w; + //keeping track of which operation happened last + reg [5:0] operation_address; + // Address wires for all C_counter DPRIO registers + // These are outputs of LUTS, changing depending + // on whether PLL_0 or PLL_1 being used + + + //Fitter will tell if FPLL1 is being used + wire fpll_1; + + // MAIN FSM + + // Synchronize locked signal + altera_std_synchronizer #( + .depth(3) + ) altera_std_synchronizer_inst ( + .clk(mgmt_clk), + .reset_n(~mgmt_reset), + .din(locked_orig), + .dout(locked) + ); + + always @(posedge clk) + begin + if (reset) + begin + dprio_cur_state <= DPRIO_IDLE; + current_state <= IDLE; + end + else + begin + current_state <= next_state; + dprio_cur_state <= dprio_next_state; + end + end + + always @(*) + begin + case(current_state) + IDLE: + begin + if (pll_start & !slave_waitrequest & usr_valid_changes) + next_state = WAIT_ON_LOCK; + else + next_state = IDLE; + end + WAIT_ON_LOCK: + begin + if (locked & dps_done & dprio_write_done) // received locked high from PLL + begin + if (slave_mode==mode_WR) //if the mode is waitrequest, then + // goto IDLE state directly + next_state = IDLE; + else + next_state = LOCKED; //otherwise go the locked state + end + else + next_state = WAIT_ON_LOCK; + end + + LOCKED: + begin + next_state = LOCKED; + end + + default: next_state = 2'bxx; + + endcase + end + + + // ask the pll to start reconfig + assign pll_start = (pll_start_asserted & (current_state==IDLE)) ; + assign pll_start_valid = (pll_start & (next_state==WAIT_ON_LOCK)) ; + + + + // WRITE OPERATIONS + assign pll_start_asserted = slave_write & (slave_address == START_REG); + + //reading the mode register to determine what mode the slave will operate + //in. + always @(posedge clk) + begin + if (reset) + slave_mode <= mode_WR; + else if (slave_write & (slave_address == MODE_REG) & !slave_waitrequest) + slave_mode <= slave_writedata[0]; + end + + //record which values user wants to change. + + //reading in the actual values that need to be reconfigged and sending + //them to the PLL + always @(posedge clk) + begin + if (reset) + begin + //reset all regs here + //BW signals reset + usr_bwctrl_value <= 0; + bwctrl_changed <= 0; + bwctrl_done_q <= 0; + //CP signals reset + usr_cp_current_value <= 0; + cp_current_changed <= 0; + cp_current_done_q <= 0; + //VCO signals reset + usr_vco_value <= 0; + vco_changed <= 0; + vco_done_q <= 0; + //DSM signals reset + usr_k_value <= 0; + dsm_k_changed <= 0; + dsm_k_done_q <= 0; + //N counter signals reset + usr_n_cnt_lo <= 0; + usr_n_cnt_hi <= 0; + usr_n_cnt_bypass_en <= 0; + usr_n_cnt_odd_duty_div_en <= 0; + n_cnt_changed <= 0; + n_cnt_done_q <= 0; + //M counter signals reset + usr_m_cnt_lo <= 0; + usr_m_cnt_hi <= 0; + usr_m_cnt_bypass_en <= 0; + usr_m_cnt_odd_duty_div_en <= 0; + m_cnt_changed <= 0; + m_cnt_done_q <= 0; + //C counter signals reset + usr_c_cnt_lo <= 0; + usr_c_cnt_hi <= 0; + usr_c_cnt_bypass_en <= 0; + usr_c_cnt_odd_duty_div_en <= 0; + any_c_cnt_changed <= 0; + all_c_cnt_done_q <= 0; + c_cnt_done_q <= 0; + //generic signals + dprio_start <= 0; + dprio_temp_m_n_c_readdata_1_q <= 0; + dprio_temp_m_n_c_readdata_2_q <= 0; + c_cnt_done_q <= 0; + //DPS signals + usr_up_dn <= 0; + usr_cnt_sel <= 0; + usr_num_shifts <= 0; + dps_changed <= 0; + //manual DPRIO signals + manual_dprio_changed <= 0; + usr_dprio_address <= 0; + usr_dprio_writedata_0 <= 0; + usr_r_w <= 0; + operation_address <= 0; + end + else + begin + if (dprio_temp_read_1) + begin + dprio_temp_m_n_c_readdata_1_q <= dprio_temp_m_n_c_readdata_1_d; + end + if (dprio_temp_read_2) + begin + dprio_temp_m_n_c_readdata_2_q <= dprio_temp_m_n_c_readdata_2_d; + end + if ((dps_done)) dps_changed <= 0; + if (dsm_k_done_d) dsm_k_done_q <= dsm_k_done_d; + if (n_cnt_done_d) n_cnt_done_q <= n_cnt_done_d; + if (m_cnt_done_d) m_cnt_done_q <= m_cnt_done_d; + if (all_c_cnt_done_d) all_c_cnt_done_q <= all_c_cnt_done_d; + if (c_cnt_done_d != 0) c_cnt_done_q <= c_cnt_done_q | c_cnt_done_d; + if (bwctrl_done_d) bwctrl_done_q <= bwctrl_done_d; + if (cp_current_done_d) cp_current_done_q <= cp_current_done_d; + if (vco_done_d) vco_done_q <= vco_done_d; + if (manual_dprio_done_d) manual_dprio_done_q <= manual_dprio_done_d; + + if (dprio_next_state == ONE) + dprio_start <= 0; + if (dprio_write_done) + begin + bwctrl_done_q <= 0; + cp_current_done_q <= 0; + vco_done_q <= 0; + dsm_k_done_q <= 0; + dsm_k_done_q <= 0; + n_cnt_done_q <= 0; + m_cnt_done_q <= 0; + all_c_cnt_done_q <= 0; + c_cnt_done_q <= 0; + dsm_k_changed <= 0; + n_cnt_changed <= 0; + m_cnt_changed <= 0; + any_c_cnt_changed <= 0; + bwctrl_changed <= 0; + cp_current_changed <= 0; + vco_changed <= 0; + manual_dprio_changed <= 0; + manual_dprio_done_q <= 0; + + end + else + begin + dsm_k_changed <= dsm_k_changed; + n_cnt_changed <= n_cnt_changed; + m_cnt_changed <= m_cnt_changed; + any_c_cnt_changed <= any_c_cnt_changed; + manual_dprio_changed <= manual_dprio_changed; + end + + + if(slave_write & !slave_waitrequest) + begin + case(slave_address) + //read in the values here from the user and act on them + DSM_REG: + begin + operation_address <= DSM_REG; + usr_k_value <= slave_writedata[31:0]; + dsm_k_changed <= 1'b1; + dsm_k_done_q <= 0; + dprio_start <= 1'b1; + end + N_REG: + begin + operation_address <= N_REG; + usr_n_cnt_lo <= slave_writedata[7:0]; + usr_n_cnt_hi <= slave_writedata[15:8]; + usr_n_cnt_bypass_en <= slave_writedata[16]; + usr_n_cnt_odd_duty_div_en <= slave_writedata[17]; + n_cnt_changed <= 1'b1; + n_cnt_done_q <= 0; + dprio_start <= 1'b1; + end + M_REG: + begin + operation_address <= M_REG; + usr_m_cnt_lo <= slave_writedata[7:0]; + usr_m_cnt_hi <= slave_writedata[15:8]; + usr_m_cnt_bypass_en <= slave_writedata[16]; + usr_m_cnt_odd_duty_div_en <= slave_writedata[17]; + m_cnt_changed <= 1'b1; + m_cnt_done_q <= 0; + dprio_start <= 1'b1; + end + //DPS_REG: + //begin + // operation_address <= DPS_REG; + // usr_num_shifts <= slave_writedata[15:0]; + // usr_up_dn <= slave_writedata[21]; + // dps_changed <= 1; + //end + C_COUNTERS_REG: + begin + operation_address <= C_COUNTERS_REG; + usr_c_cnt_lo <= slave_writedata[7:0]; + usr_c_cnt_hi <= slave_writedata[15:8]; + usr_c_cnt_bypass_en <= slave_writedata[16]; + usr_c_cnt_odd_duty_div_en <= slave_writedata[17]; + any_c_cnt_changed <= 1'b1; + all_c_cnt_done_q <= 0; + dprio_start <= 1'b1; + end + BWCTRL_REG: + begin + usr_bwctrl_value <= slave_writedata[3:0]; + bwctrl_changed <= 1'b1; + bwctrl_done_q <= 0; + dprio_start <= 1'b1; + operation_address <= BWCTRL_REG; + end + CP_CURRENT_REG: + begin + usr_cp_current_value <= slave_writedata[2:0]; + cp_current_changed <= 1'b1; + cp_current_done_q <= 0; + dprio_start <= 1'b1; + operation_address <= CP_CURRENT_REG; + end + //VCO_REG: + //begin + // usr_vco_value <= slave_writedata[0]; + // vco_changed <= 1'b1; + // vco_done_q <= 0; + // dprio_start <= 1'b1; + // operation_address <= VCO_REG; + //end + //ANY_DPRIO: + //begin + // operation_address <= ANY_DPRIO; + // manual_dprio_changed <= 1'b1; + // usr_dprio_address <= slave_writedata[5:0]; + // usr_dprio_writedata_0 <= slave_writedata[21:6]; + // usr_r_w <= slave_writedata[22]; + // manual_dprio_done_q <= 0; + // dprio_start <= 1'b1; + //end + endcase + end + end + end + //C Counter assigning values to the 2-d array of values for each C counter + + reg [4:0] j; + always @(posedge clk) + begin + + if (reset) + begin + c_cnt_changed[17:0] <= 0; + for (j = 0; j < number_of_counters; j = j + 1'b1) + begin : c_cnt_reset + temp_c_cnt_bypass_en[j] <= 0; + temp_c_cnt_odd_duty_div_en[j] <= 0; + end + end + else + begin + if (dprio_write_done) + begin + c_cnt_changed <= 0; + end + if (any_c_cnt_changed && (operation_address == C_COUNTERS_REG)) + begin + temp_c_cnt_bypass_en [5] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [5] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [5] <= 1'b1; + end + end + end + + + //logic to handle which writes the user indicated and wants to start. + assign usr_valid_changes =dsm_k_changed| any_c_cnt_changed |n_cnt_changed | m_cnt_changed | dps_changed_valid |manual_dprio_changed |cp_current_changed|bwctrl_changed|vco_changed; + + + //start the reconfig operations by writing to the DPRIO + reg break_loop; + reg [4:0] i; + always @(*) + begin + dprio_temp_read_1 = 0; + dprio_temp_read_2 = 0; + dprio_temp_m_n_c_readdata_1_d = 0; + dprio_temp_m_n_c_readdata_2_d = 0; + break_loop = 0; + dprio_next_state = DPRIO_IDLE; + avmm_dprio_write = 0; + avmm_dprio_read = 0; + avmm_dprio_address = 0; + avmm_dprio_writedata = 0; + avmm_dprio_byteen = 0; + dprio_write_done = 1; + manual_dprio_done_d = 0; + n_cnt_done_d = 0; + dsm_k_done_d = 0; + dsm_k_ready_false_done_d = 0; + m_cnt_done_d = 0; + c_cnt_done_d[17:0] = 0; + all_c_cnt_done_d = 0; + bwctrl_done_d = 0; + cp_current_done_d = 0; + vco_done_d = 0; + i = 0; + + // Deassert dprio_write_done so it doesn't reset mif_reg_asserted (toggled writes) + if (dprio_start) + dprio_write_done = 0; + + if (current_state == WAIT_ON_LOCK) + begin + case (dprio_cur_state) + ONE: + begin + if (n_cnt_changed & !n_cnt_done_q) + begin + dprio_write_done = 0; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + dprio_next_state = TWO; + avmm_dprio_address = N_CNT_DIV_ADDR; + avmm_dprio_writedata[7:0] = usr_n_cnt_lo; + avmm_dprio_writedata[15:8] = usr_n_cnt_hi; + end + else if (m_cnt_changed & !m_cnt_done_q) + begin + dprio_write_done = 0; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + dprio_next_state = TWO; + avmm_dprio_address = M_CNT_DIV_ADDR; + avmm_dprio_writedata[7:0] = usr_m_cnt_lo; + avmm_dprio_writedata[15:8] = usr_m_cnt_hi; + end + else if (any_c_cnt_changed & !all_c_cnt_done_q) + begin + + for (i = 0; (i < number_of_counters) & !break_loop; i = i + 1'b1) + begin : c_cnt_write_hilo + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + dprio_write_done = 0; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + dprio_next_state = TWO; + if (fpll_1) avmm_dprio_address = C_CNT_0_DIV_ADDR + C_CNT_0_DIV_ADDR_DPRIO_1 - i; + else avmm_dprio_address = C_CNT_0_DIV_ADDR + i; + avmm_dprio_writedata[7:0] = usr_c_cnt_lo; + avmm_dprio_writedata[15:8] = usr_c_cnt_hi; + //To break from the loop, since only one counter + //is addressed at a time + break_loop = 1'b1; + end + end + end + else if (dsm_k_changed & !dsm_k_done_q) + begin + dprio_write_done = 0; + avmm_dprio_write = 0; + dprio_next_state = TWO; + end + else if (bwctrl_changed & !bwctrl_done_q) + begin + dprio_write_done = 0; + avmm_dprio_write = 0; + dprio_next_state = TWO; + end + else if (cp_current_changed & !cp_current_done_q) + begin + dprio_write_done = 0; + avmm_dprio_write = 0; + dprio_next_state = TWO; + end + else if (vco_changed & !vco_done_q) + begin + dprio_write_done = 0; + avmm_dprio_write = 0; + dprio_next_state = TWO; + end + else if (manual_dprio_changed & !manual_dprio_done_q) + begin + dprio_write_done = 0; + avmm_dprio_byteen = 2'b11; + dprio_next_state = TWO; + avmm_dprio_write = usr_r_w; + avmm_dprio_address = usr_dprio_address; + avmm_dprio_writedata[15:0] = usr_dprio_writedata_0; + end + else dprio_next_state = DPRIO_IDLE; + end + + TWO: + begin + //handle reading the two setting bits on n_cnt, then + //writing them back while preserving other bits. + //Issue two consecutive reads then wait; readLatency=3 + dprio_write_done = 0; + dprio_next_state = THREE; + avmm_dprio_byteen = 2'b11; + avmm_dprio_read = 1'b1; + if (n_cnt_changed & !n_cnt_done_q) + begin + avmm_dprio_address = N_CNT_BYPASS_EN_ADDR; + end + else if (m_cnt_changed & !m_cnt_done_q) + begin + avmm_dprio_address = M_CNT_BYPASS_EN_ADDR; + end + + else if (any_c_cnt_changed & !all_c_cnt_done_q) + begin + for (i = 5; (i < number_of_counters) & !break_loop; i = i + 1'b1) + begin : c_cnt_read_bypass + if (fpll_1) + begin + if (i > 13) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_BYPASS_EN_ADDR; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_BYPASS_EN_ADDR; + break_loop = 1'b1; + end + end + end + else + begin + if (i < 4) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_BYPASS_EN_ADDR; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_BYPASS_EN_ADDR; + break_loop = 1'b1; + end + end + end + end + end + //reading the K ready 16 bit word. Need to write 0 to it + //afterwards to indicate that K has not been done writing + else if (dsm_k_changed & !dsm_k_done_q) + begin + avmm_dprio_address = DSM_K_READY_ADDR; + dprio_next_state = FOUR; + end + else if (bwctrl_changed & !bwctrl_done_q) + begin + avmm_dprio_address = BWCTRL_ADDR; + dprio_next_state = FOUR; + end + else if (cp_current_changed & !cp_current_done_q) + begin + avmm_dprio_address = CP_CURRENT_ADDR; + dprio_next_state = FOUR; + end + else if (vco_changed & !vco_done_q) + begin + avmm_dprio_address = VCO_ADDR; + dprio_next_state = FOUR; + end + else if (manual_dprio_changed & !manual_dprio_done_q) + begin + avmm_dprio_read = ~usr_r_w; + avmm_dprio_address = usr_dprio_address; + dprio_next_state = DPRIO_DONE; + end + else dprio_next_state = DPRIO_IDLE; + end + THREE: + begin + dprio_write_done = 0; + avmm_dprio_byteen = 2'b11; + avmm_dprio_read = 1'b1; + dprio_next_state = FOUR; + if (n_cnt_changed & !n_cnt_done_q) + begin + avmm_dprio_address = N_CNT_ODD_DIV_EN_ADDR; + end + else if (m_cnt_changed & !m_cnt_done_q) + begin + avmm_dprio_address = M_CNT_ODD_DIV_EN_ADDR; + end + else if (any_c_cnt_changed & !all_c_cnt_done_q) + begin + for (i = 5; (i < number_of_counters) & !break_loop; i = i + 1'b1) + begin : c_cnt_read_odd_div + if (fpll_1) + begin + if (i > 13) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_ODD_DIV_EN_ADDR; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_ODD_DIV_EN_ADDR; + break_loop = 1'b1; + end + end + end + else + begin + if (i < 4) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_ODD_DIV_EN_ADDR; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_ODD_DIV_EN_ADDR; + break_loop = 1'b1; + end + end + end + end + end + else dprio_next_state = DPRIO_IDLE; + end + FOUR: + begin + dprio_temp_read_1 = 1'b1; + dprio_write_done = 0; + if (vco_changed|cp_current_changed|bwctrl_changed|dsm_k_changed|n_cnt_changed|m_cnt_changed|any_c_cnt_changed) + begin + dprio_temp_m_n_c_readdata_1_d = dprio_readdata; + dprio_next_state = FIVE; + end + else dprio_next_state = DPRIO_IDLE; + end + FIVE: + begin + dprio_write_done = 0; + dprio_temp_read_2 = 1'b1; + if (vco_changed|cp_current_changed|bwctrl_changed|dsm_k_changed|n_cnt_changed|m_cnt_changed|any_c_cnt_changed) + begin + //this is where DSM ready value comes. + //Need to store in a register to be used later + dprio_temp_m_n_c_readdata_2_d = dprio_readdata; + dprio_next_state = SIX; + end + else dprio_next_state = DPRIO_IDLE; + end + SIX: + begin + dprio_write_done = 0; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + dprio_next_state = SEVEN; + avmm_dprio_writedata = dprio_temp_m_n_c_readdata_1_q; + if (n_cnt_changed & !n_cnt_done_q) + begin + avmm_dprio_address = N_CNT_BYPASS_EN_ADDR; + avmm_dprio_writedata[5] = usr_n_cnt_bypass_en; + end + else if (m_cnt_changed & !m_cnt_done_q) + begin + avmm_dprio_address = M_CNT_BYPASS_EN_ADDR; + avmm_dprio_writedata[4] = usr_m_cnt_bypass_en; + end + else if (any_c_cnt_changed & !all_c_cnt_done_q) + begin + for (i = 5; (i < number_of_counters) & !break_loop; i = i + 1'b1) + begin : c_cnt_write_bypass + if (fpll_1) + begin + if (i > 13) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_BYPASS_EN_ADDR; + avmm_dprio_writedata[i-14] = temp_c_cnt_bypass_en[i]; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_BYPASS_EN_ADDR; + avmm_dprio_writedata[i] = temp_c_cnt_bypass_en[i]; + break_loop = 1'b1; + end + end + end + else + begin + if (i < 4) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_BYPASS_EN_ADDR; + avmm_dprio_writedata[3-i] = temp_c_cnt_bypass_en[i]; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_BYPASS_EN_ADDR; + avmm_dprio_writedata[17-i] = temp_c_cnt_bypass_en[i]; + break_loop = 1'b1; + end + end + end + end + end + else if (dsm_k_changed & !dsm_k_done_q) + begin + avmm_dprio_write = 0; + end + else if (bwctrl_changed & !bwctrl_done_q) + begin + avmm_dprio_write = 0; + end + else if (cp_current_changed & !cp_current_done_q) + begin + avmm_dprio_write = 0; + end + else if (vco_changed & !vco_done_q) + begin + avmm_dprio_write = 0; + end + else dprio_next_state = DPRIO_IDLE; + end + SEVEN: + begin + dprio_write_done = 0; + dprio_next_state = EIGHT; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + avmm_dprio_writedata = dprio_temp_m_n_c_readdata_2_q; + if (n_cnt_changed & !n_cnt_done_q) + begin + avmm_dprio_address = N_CNT_ODD_DIV_EN_ADDR; + avmm_dprio_writedata[5] = usr_n_cnt_odd_duty_div_en; + n_cnt_done_d = 1'b1; + end + else if (m_cnt_changed & !m_cnt_done_q) + begin + avmm_dprio_address = M_CNT_ODD_DIV_EN_ADDR; + avmm_dprio_writedata[4] = usr_m_cnt_odd_duty_div_en; + m_cnt_done_d = 1'b1; + end + + else if (any_c_cnt_changed & !all_c_cnt_done_q) + begin + for (i = 5; (i < number_of_counters) & !break_loop; i = i + 1'b1) + begin : c_cnt_write_odd_div + if (fpll_1) + begin + if (i > 13) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_ODD_DIV_EN_ADDR; + avmm_dprio_writedata[i-14] = temp_c_cnt_odd_duty_div_en[i]; + c_cnt_done_d[i] = 1'b1; + //have to OR the signals to prevent + //overwriting of previous dones + c_cnt_done_d = c_cnt_done_d | c_cnt_done_q; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_ODD_DIV_EN_ADDR; + avmm_dprio_writedata[i] = temp_c_cnt_odd_duty_div_en[i]; + c_cnt_done_d[i] = 1'b1; + c_cnt_done_d = c_cnt_done_d | c_cnt_done_q; + break_loop = 1'b1; + end + end + end + else + begin + if (i < 4) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_ODD_DIV_EN_ADDR; + avmm_dprio_writedata[3-i] = temp_c_cnt_odd_duty_div_en[i]; + c_cnt_done_d[i] = 1'b1; + //have to OR the signals to prevent + //overwriting of previous dones + c_cnt_done_d = c_cnt_done_d | c_cnt_done_q; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_ODD_DIV_EN_ADDR; + avmm_dprio_writedata[17-i] = temp_c_cnt_odd_duty_div_en[i]; + c_cnt_done_d[i] = 1'b1; + c_cnt_done_d = c_cnt_done_d | c_cnt_done_q; + break_loop = 1'b1; + end + end + end + end + end + else if (dsm_k_changed & !dsm_k_done_q) + begin + avmm_dprio_address = DSM_K_READY_ADDR; + avmm_dprio_writedata[DSM_K_READY_BIT_INDEX] = 1'b0; + dsm_k_ready_false_done_d = 1'b1; + end + else if (bwctrl_changed & !bwctrl_done_q) + begin + avmm_dprio_address = BWCTRL_ADDR; + avmm_dprio_writedata[3:0] = usr_bwctrl_value; + bwctrl_done_d = 1'b1; + end + else if (cp_current_changed & !cp_current_done_q) + begin + avmm_dprio_address = CP_CURRENT_ADDR; + avmm_dprio_writedata[2:0] = usr_cp_current_value; + cp_current_done_d = 1'b1; + end + else if (vco_changed & !vco_done_q) + begin + avmm_dprio_address = VCO_ADDR; + avmm_dprio_writedata[8] = usr_vco_value; + vco_done_d = 1'b1; + end + + + //if all C_cnt that were changed are done, then assert all_c_cnt_done + if (c_cnt_done_d == c_cnt_changed) + all_c_cnt_done_d = 1'b1; + if (n_cnt_changed & n_cnt_done_d) + dprio_next_state = DPRIO_DONE; + if (any_c_cnt_changed & !all_c_cnt_done_d & !all_c_cnt_done_q) + dprio_next_state = ONE; + else if (m_cnt_changed & !m_cnt_done_d & !m_cnt_done_q) + dprio_next_state = ONE; + else if (dsm_k_changed & !dsm_k_ready_false_done_d) + dprio_next_state = TWO; + else if (dsm_k_changed & !dsm_k_done_q) + dprio_next_state = EIGHT; + else if (bwctrl_changed & !bwctrl_done_d) + dprio_next_state = TWO; + else if (cp_current_changed & !cp_current_done_d) + dprio_next_state = TWO; + else if (vco_changed & !vco_done_d) + dprio_next_state = TWO; + else + begin + dprio_next_state = DPRIO_DONE; + dprio_write_done = 1'b1; + end + end + //finish the rest of the DSM reads/writes + //writing k value, writing k_ready to 1. + EIGHT: + begin + dprio_write_done = 0; + dprio_next_state = NINE; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + if (dsm_k_changed & !dsm_k_done_q) + begin + avmm_dprio_address = DSM_K_FRACTIONAL_DIVISION_ADDR_0; + avmm_dprio_writedata[15:0] = usr_k_value[15:0]; + end + end + NINE: + begin + dprio_write_done = 0; + dprio_next_state = TEN; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + if (dsm_k_changed & !dsm_k_done_q) + begin + avmm_dprio_address = DSM_K_FRACTIONAL_DIVISION_ADDR_1; + avmm_dprio_writedata[15:0] = usr_k_value[31:16]; + end + end + TEN: + begin + dprio_write_done = 0; + dprio_next_state = ONE; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + if (dsm_k_changed & !dsm_k_done_q) + begin + avmm_dprio_address = DSM_K_READY_ADDR; + //already have the readdata for DSM_K_READY_ADDR since we read it + //earlier. Just reuse here + avmm_dprio_writedata = dprio_temp_m_n_c_readdata_2_q; + avmm_dprio_writedata[DSM_K_READY_BIT_INDEX] = 1'b1; + dsm_k_done_d = 1'b1; + end + end + DPRIO_DONE: + begin + dprio_write_done = 1'b1; + if (dprio_start) dprio_next_state = DPRIO_IDLE; + else dprio_next_state = DPRIO_DONE; + end + DPRIO_IDLE: + begin + if (dprio_start) dprio_next_state = ONE; + else dprio_next_state = DPRIO_IDLE; + end + default: dprio_next_state = 4'bxxxx; + endcase + end + + end + + + //assert the waitreq signal according to the state of the slave + assign slave_waitrequest = (slave_mode==mode_WR) ? ((locked === 1'b1) ? (((current_state==WAIT_ON_LOCK) & !dprio_write_done) | !dps_done |reset|!dprio_init_done) : 1'b1) : 1'b0; + + + dyn_phase_shift dyn_phase_shift_inst ( + .clk(clk), + .reset(reset), + .phase_done(phase_done), + .pll_start_valid(pll_start_valid), + .dps_changed(dps_changed), + .dps_changed_valid(dps_changed_valid), + .dprio_write_done(dprio_write_done), + .usr_num_shifts(usr_num_shifts), + .usr_cnt_sel(usr_cnt_sel), + .usr_up_dn(usr_up_dn), + .locked(locked), + .dps_done(dps_done), + .phase_en(phase_en), + .up_dn(up_dn), + .cnt_sel(cnt_sel)); + defparam dyn_phase_shift_inst.device_family = device_family; + + assign dprio_clk = clk; + self_reset self_reset_inst (mgmt_reset, clk, reset, dprio_init_reset); + + dprio_mux dprio_mux_inst ( + .init_dprio_address(init_dprio_address), + .init_dprio_read(init_dprio_read), + .init_dprio_byteen(init_dprio_byteen), + .init_dprio_write(init_dprio_write), + .init_dprio_writedata(init_dprio_writedata), + + + .init_atpgmode(init_atpgmode), + .init_mdio_dis(init_mdio_dis), + .init_scanen(init_scanen), + .init_ser_shift_load(init_ser_shift_load), + .dprio_init_done(dprio_init_done), + + // Inputs from avmm master + .avmm_dprio_address(avmm_dprio_address), + .avmm_dprio_read(avmm_dprio_read), + .avmm_dprio_byteen(avmm_dprio_byteen), + .avmm_dprio_write(avmm_dprio_write), + .avmm_dprio_writedata(avmm_dprio_writedata), + + .avmm_atpgmode(avmm_atpgmode), + .avmm_mdio_dis(avmm_mdio_dis), + .avmm_scanen(avmm_scanen), + + // Outputs to fpll + .dprio_address(dprio_address), + .dprio_read(dprio_read), + .dprio_byteen(dprio_byteen), + .dprio_write(dprio_write), + .dprio_writedata(dprio_writedata), + + .atpgmode(dprio_atpgmode), + .mdio_dis(dprio_mdio_dis), + .scanen(dprio_scanen), + .ser_shift_load(dprio_ser_shift_load) + ); + + + fpll_dprio_init fpll_dprio_init_inst ( + .clk(clk), + .reset_n(~reset), + .locked(locked), + + //outputs + .dprio_address(init_dprio_address), + .dprio_read(init_dprio_read), + .dprio_byteen(init_dprio_byteen), + .dprio_write(init_dprio_write), + .dprio_writedata(init_dprio_writedata), + + .atpgmode(init_atpgmode), + .mdio_dis(init_mdio_dis), + .scanen(init_scanen), + .ser_shift_load(init_ser_shift_load), + .dprio_init_done(dprio_init_done)); + + //address luts, to be reconfigged by the Fitter + //FPLL_1 or 0 address lut + generic_lcell_comb lcell_fpll_0_1 ( + .dataa(1'b0), + .combout (fpll_1)); + defparam lcell_fpll_0_1.lut_mask = 64'hAAAAAAAAAAAAAAAA; + defparam lcell_fpll_0_1.dont_touch = "on"; + defparam lcell_fpll_0_1.family = device_family; + + + wire dprio_read_combout; + generic_lcell_comb lcell_dprio_read ( + .dataa(fpll_1), + .datab(dprio_read), + .datac(1'b0), + .datad(1'b0), + .datae(1'b0), + .dataf(1'b0), + .combout (dprio_read_combout)); + defparam lcell_dprio_read.lut_mask = 64'hCCCCCCCCCCCCCCCC; + defparam lcell_dprio_read.dont_touch = "on"; + defparam lcell_dprio_read.family = device_family; + + + + + + //assign reconfig_to_pll signals + assign reconfig_to_pll[0] = dprio_clk; + assign reconfig_to_pll[1] = ~dprio_init_reset; + assign reconfig_to_pll[2] = dprio_write; + assign reconfig_to_pll[3] = dprio_read_combout; + assign reconfig_to_pll[9:4] = dprio_address; + assign reconfig_to_pll[25:10] = dprio_writedata; + assign reconfig_to_pll[27:26] = dprio_byteen; + assign reconfig_to_pll[28] = dprio_ser_shift_load; + assign reconfig_to_pll[29] = dprio_mdio_dis; + assign reconfig_to_pll[30] = phase_en; + assign reconfig_to_pll[31] = up_dn; + assign reconfig_to_pll[36:32] = cnt_sel; + assign reconfig_to_pll[37] = dprio_scanen; + assign reconfig_to_pll[38] = dprio_atpgmode; + //assign reconfig_to_pll[40:37] = clken; + assign reconfig_to_pll[63:39] = 0; + + //assign reconfig_from_pll signals + assign dprio_readdata = reconfig_from_pll [15:0]; + assign locked_orig = reconfig_from_pll [16]; + assign phase_done = reconfig_from_pll [17]; + +endmodule diff --git a/sys/pll_q13.qip b/sys/pll_q13.qip index 13a7ed4..78e7e40 100644 --- a/sys/pll_q13.qip +++ b/sys/pll_q13.qip @@ -1,6 +1,4 @@ set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll.13.qip ] set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_hdmi.13.qip ] set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_audio.13.qip ] -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) pll_cfg.v ] -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) pll_cfg/altera_pll_reconfig_core.v ] -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) pll_cfg/altera_pll_reconfig_top.v ] +set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_cfg.qip ] diff --git a/sys/sys.tcl b/sys/sys.tcl index ce83683..93b6247 100644 --- a/sys/sys.tcl +++ b/sys/sys.tcl @@ -16,13 +16,6 @@ set_location_assignment PIN_V10 -to ADC_SCK set_location_assignment PIN_AC4 -to ADC_SDI set_location_assignment PIN_AD4 -to ADC_SDO -#============================================================ -# ARDUINO -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[*] -set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to ARDUINO_IO[*] -set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to ARDUINO_IO[*] - #============================================================ # I2C LEDS/BUTTONS #============================================================ diff --git a/sys/sys_top.sdc b/sys/sys_top.sdc index 0d8763f..c598983 100644 --- a/sys/sys_top.sdc +++ b/sys/sys_top.sdc @@ -25,6 +25,7 @@ set_false_path -from [get_ports {KEY*}] set_false_path -from [get_ports {BTN_*}] set_false_path -to [get_ports {LED_*}] set_false_path -to [get_ports {VGA_*}] +set_false_path -from [get_ports {VGA_EN}] set_false_path -to [get_ports {AUDIO_SPDIF}] set_false_path -to [get_ports {AUDIO_L}] set_false_path -to [get_ports {AUDIO_R}] @@ -34,6 +35,7 @@ set_false_path -from {cfg[*]} set_false_path -from {VSET[*]} set_false_path -to {wcalc[*] hcalc[*]} set_false_path -to {hdmi_width[*] hdmi_height[*]} +set_false_path -to {deb_* btn_en btn_up} set_multicycle_path -to {*_osd|osd_vcnt*} -setup 2 set_multicycle_path -to {*_osd|osd_vcnt*} -hold 1 @@ -70,4 +72,5 @@ set_false_path -from {ascal|o_htotal* ascal|o_vtotal*} set_false_path -from {ascal|o_hsstart* ascal|o_vsstart* ascal|o_hsend* ascal|o_vsend*} set_false_path -from {ascal|o_hsize* ascal|o_vsize*} -set_false_path -from {mcp23009|sd_cd} +set_false_path -from {mcp23009|flg_*} +set_false_path -to {sysmem|fpga_interfaces|clocks_resets*} diff --git a/sys/sys_top.v b/sys/sys_top.v index 6de0011..74156ce 100644 --- a/sys/sys_top.v +++ b/sys/sys_top.v @@ -72,7 +72,7 @@ module sys_top output [5:0] VGA_R, output [5:0] VGA_G, output [5:0] VGA_B, - inout VGA_HS, // VGA_HS is secondary SD card detect when VGA_EN = 1 (inactive) + inout VGA_HS, output VGA_VS, input VGA_EN, // active low @@ -125,27 +125,22 @@ module sys_top ); ////////////////////// Secondary SD /////////////////////////////////// -wire SD_CS, SD_CLK, SD_MOSI; +wire SD_CS, SD_CLK, SD_MOSI, SD_MISO, SD_CD; `ifndef MISTER_DUAL_SDRAM - wire sd_miso = SW[3] | SDIO_DAT[0]; + assign SD_CD = mcp_en ? mcp_sdcd : SDCD_SPDIF; + assign SD_MISO = SD_CD | (mcp_en ? SD_SPI_MISO : (VGA_EN | SDIO_DAT[0])); + assign SD_SPI_CS = mcp_en ? (mcp_sdcd ? 1'bZ : SD_CS) : (sog & ~cs1 & ~VGA_EN) ? 1'b1 : 1'bZ; + assign SD_SPI_CLK = (~mcp_en | mcp_sdcd) ? 1'bZ : SD_CLK; + assign SD_SPI_MOSI = (~mcp_en | mcp_sdcd) ? 1'bZ : SD_MOSI; + assign {SDIO_CLK,SDIO_CMD,SDIO_DAT} = av_dis ? 6'bZZZZZZ : (mcp_en | (SDCD_SPDIF & ~SW[2])) ? {vga_g,vga_r,vga_b} : {SD_CLK,SD_MOSI,SD_CS,3'bZZZ}; `else - wire sd_miso = 1; + assign SD_CD = mcp_sdcd; + assign SD_MISO = mcp_sdcd | SD_SPI_MISO; + assign SD_SPI_CS = mcp_sdcd ? 1'bZ : SD_CS; + assign SD_SPI_CLK = mcp_sdcd ? 1'bZ : SD_CLK; + assign SD_SPI_MOSI = mcp_sdcd ? 1'bZ : SD_MOSI; `endif -wire SD_MISO = mcp_sdcd ? sd_miso : SD_SPI_MISO; - -`ifndef MISTER_DUAL_SDRAM - assign SDIO_DAT[2:1]= 2'bZZ; - assign SDIO_DAT[3] = SW[3] ? 1'bZ : SD_CS; - assign SDIO_CLK = SW[3] ? 1'bZ : SD_CLK; - assign SDIO_CMD = SW[3] ? 1'bZ : SD_MOSI; - assign SD_SPI_CS = mcp_sdcd ? ((~VGA_EN & sog & ~cs1) ? 1'b1 : 1'bZ) : SD_CS; -`else - assign SD_SPI_CS = mcp_sdcd ? 1'bZ : SD_CS; -`endif - -assign SD_SPI_CLK = mcp_sdcd ? 1'bZ : SD_CLK; -assign SD_SPI_MOSI = mcp_sdcd ? 1'bZ : SD_MOSI; ////////////////////// LEDs/Buttons /////////////////////////////////// @@ -157,36 +152,58 @@ wire led_d = led_disk[1] ? ~led_disk[0] : ~(led_disk[0] | gp_out[29]); wire led_u = ~led_user; wire led_locked; -`ifndef MISTER_DUAL_SDRAM - assign LED_POWER = (SW[3] | led_p) ? 1'bZ : 1'b0; - assign LED_HDD = (SW[3] | led_d) ? 1'bZ : 1'b0; - assign LED_USER = (SW[3] | led_u) ? 1'bZ : 1'b0; -`endif - -//LEDs on main board +//LEDs on de10-nano board assign LED = (led_overtake & led_state) | (~led_overtake & {1'b0,led_locked,1'b0, ~led_p, 1'b0, ~led_d, 1'b0, ~led_u}); -wire btn_r, btn_o, btn_u; -`ifdef MISTER_DUAL_SDRAM - assign {btn_r,btn_o,btn_u} = SW[3] ? {mcp_btn[1],mcp_btn[2],mcp_btn[0]} : ~{SDRAM2_DQ[9],SDRAM2_DQ[13],SDRAM2_DQ[11]}; -`else - assign {btn_r,btn_o,btn_u} = ~{BTN_RESET,BTN_OSD,BTN_USER} | {mcp_btn[1],mcp_btn[2],mcp_btn[0]}; -`endif - wire [2:0] mcp_btn; wire mcp_sdcd; +wire mcp_en; +wire mcp_mode; mcp23009 mcp23009 ( .clk(FPGA_CLK2_50), .btn(mcp_btn), .led({led_p, led_d, led_u}), - .sd_cd(mcp_sdcd), + .flg_sd_cd(mcp_sdcd), + .flg_present(mcp_en), + .flg_mode(mcp_mode), .scl(IO_SCL), .sda(IO_SDA) ); +wire io_dig = mcp_en ? mcp_mode : SW[3]; + +`ifndef MISTER_DUAL_SDRAM + wire av_dis = io_dig | VGA_EN; + assign LED_POWER = av_dis ? 1'bZ : mcp_en ? de1 : led_p ? 1'bZ : 1'b0; + assign LED_HDD = av_dis ? 1'bZ : mcp_en ? (sog & ~cs1) : led_d ? 1'bZ : 1'b0; + assign LED_USER = av_dis ? 1'bZ : mcp_en ? ~vga_tx_clk : led_u ? 1'bZ : 1'b0; + wire BTN_DIS = VGA_EN; +`else + wire BTN_RESET = SDRAM2_DQ[9]; + wire BTN_OSD = SDRAM2_DQ[13]; + wire BTN_USER = SDRAM2_DQ[11]; + wire BTN_DIS = SDRAM2_DQ[15]; +`endif + +reg BTN_EN = 0; +reg [25:0] btn_timeout = 0; +initial btn_timeout = 0; +always @(posedge FPGA_CLK2_50) begin + reg btn_up = 0; + reg btn_en = 0; + + btn_up <= BTN_RESET & BTN_OSD & BTN_USER; + if(~reset & btn_up & ~&btn_timeout) btn_timeout <= btn_timeout + 1'd1; + btn_en <= ~BTN_DIS; + BTN_EN <= &btn_timeout & btn_en; +end + +wire btn_r = (mcp_en | SW[3]) ? mcp_btn[1] : (BTN_EN & ~BTN_RESET); +wire btn_o = (mcp_en | SW[3]) ? mcp_btn[2] : (BTN_EN & ~BTN_OSD ); +wire btn_u = (mcp_en | SW[3]) ? mcp_btn[0] : (BTN_EN & ~BTN_USER ); reg btn_user, btn_osd; always @(posedge FPGA_CLK2_50) begin @@ -212,7 +229,7 @@ end // gp_in[31] = 0 - quick flag that FPGA is initialized (HPS reads 1 when FPGA is not in user mode) // used to avoid lockups while JTAG loading -wire [31:0] gp_in = {1'b0, btn_user | btn[1], btn_osd | btn[0], SW[3], 8'd0, io_ver, io_ack, io_wide, io_dout | io_dout_sys}; +wire [31:0] gp_in = {1'b0, btn_user | btn[1], btn_osd | btn[0], io_dig, 8'd0, io_ver, io_ack, io_wide, io_dout | io_dout_sys}; wire [31:0] gp_out; wire [1:0] io_ver = 1; // 0 - obsolete. 1 - optimized HPS I/O. 2,3 - reserved for future. @@ -226,7 +243,7 @@ wire io_ss1 = gp_outr[19]; wire io_ss2 = gp_outr[20]; `ifndef MISTER_DEBUG_NOHDMI -wire io_osd_hdmi = io_ss1 & ~io_ss0; + wire io_osd_hdmi = io_ss1 & ~io_ss0; `endif wire io_fpga = ~io_ss1 & io_ss0; @@ -267,14 +284,14 @@ cyclonev_hps_interface_mpu_general_purpose h2f_gp reg [15:0] cfg; - reg cfg_set = 0; -wire vga_fb = cfg[12] | vga_force_scaler; `ifdef MISTER_DEBUG_NOHDMI -wire direct_video = 1; + wire vga_fb = 0; + wire direct_video = 1; `else -wire direct_video = cfg[10]; + wire vga_fb = cfg[12] | vga_force_scaler; + wire direct_video = cfg[10]; `endif wire audio_96k = cfg[6]; @@ -283,7 +300,11 @@ wire io_osd_vga = io_ss1 & ~io_ss2; `ifndef MISTER_DUAL_SDRAM wire ypbpr_en = cfg[5]; wire sog = cfg[9]; - wire vga_scaler = cfg[2] | vga_force_scaler; + `ifdef MISTER_DEBUG_NOHDMI + wire vga_scaler = 0; + `else + wire vga_scaler = cfg[2] | vga_force_scaler; + `endif `endif reg cfg_custom_t = 0; @@ -657,120 +678,120 @@ wire hdmi_vs, hdmi_hs, hdmi_de, hdmi_vbl, hdmi_brd; wire freeze; `ifndef MISTER_DEBUG_NOHDMI -wire clk_hdmi = hdmi_clk_out; + wire clk_hdmi = hdmi_clk_out; -ascal -#( - .RAMBASE(32'h20000000), -`ifdef MISTER_SMALL_VBUF - .RAMSIZE(32'h00200000), -`else - .RAMSIZE(32'h00800000), -`endif -`ifndef MISTER_FB - .PALETTE2("false"), -`else - `ifndef MISTER_FB_PALETTE + ascal + #( + .RAMBASE(32'h20000000), + `ifdef MISTER_SMALL_VBUF + .RAMSIZE(32'h00200000), + `else + .RAMSIZE(32'h00800000), + `endif + `ifndef MISTER_FB .PALETTE2("false"), + `else + `ifndef MISTER_FB_PALETTE + .PALETTE2("false"), + `endif `endif -`endif -`ifdef MISTER_DISABLE_ADAPTIVE - .ADAPTIVE("false"), -`endif -`ifdef MISTER_DOWNSCALE_NN - .DOWNSCALE_NN("true"), -`endif - .FRAC(8), - .N_DW(128), - .N_AW(28) -) -ascal -( - .reset_na (~reset_req), - .run (1), - .freeze (freeze), - - .i_clk (clk_ihdmi), - .i_ce (ce_hpix), - .i_r (hr_out), - .i_g (hg_out), - .i_b (hb_out), - .i_hs (hhs_fix), - .i_vs (hvs_fix), - .i_fl (f1), - .i_de (hde_emu), - .iauto (1), - .himin (0), - .himax (0), - .vimin (0), - .vimax (0), - - .o_clk (clk_hdmi), - .o_ce (scaler_out), - .o_r (hdmi_data[23:16]), - .o_g (hdmi_data[15:8]), - .o_b (hdmi_data[7:0]), - .o_hs (hdmi_hs), - .o_vs (hdmi_vs), - .o_de (hdmi_de), - .o_vbl (hdmi_vbl), - .o_brd (hdmi_brd), - .o_lltune (lltune), - .htotal (WIDTH + HFP + HBP + HS[11:0]), - .hsstart (WIDTH + HFP), - .hsend (WIDTH + HFP + HS[11:0]), - .hdisp (WIDTH), - .hmin (hmin), - .hmax (hmax), - .vtotal (HEIGHT + VFP + VBP + VS[11:0]), - .vsstart (HEIGHT + VFP), - .vsend (HEIGHT + VFP + VS[11:0]), - .vdisp (HEIGHT), - .vmin (vmin), - .vmax (vmax), - .vrr (vrr_mode), - .vrrmax (HEIGHT + VBP + VS[11:0] + 12'd1), - - .mode ({~lowlat,LFB_EN ? LFB_FLT : |scaler_flt,2'b00}), - .poly_clk (clk_sys), - .poly_a (coef_addr), - .poly_dw (coef_data), - .poly_wr (coef_wr), - - .pal1_clk (clk_pal), - .pal1_dw (pal_d), - .pal1_a (pal_a), - .pal1_wr (pal_wr), - -`ifdef MISTER_FB - `ifdef MISTER_FB_PALETTE - .pal2_clk (fb_pal_clk), - .pal2_dw (fb_pal_d), - .pal2_dr (fb_pal_q), - .pal2_a (fb_pal_a), - .pal2_wr (fb_pal_wr), - .pal_n (fb_en), + `ifdef MISTER_DISABLE_ADAPTIVE + .ADAPTIVE("false"), `endif -`endif + `ifdef MISTER_DOWNSCALE_NN + .DOWNSCALE_NN("true"), + `endif + .FRAC(8), + .N_DW(128), + .N_AW(28) + ) + ascal + ( + .reset_na (~reset_req), + .run (1), + .freeze (freeze), - .o_fb_ena (FB_EN), - .o_fb_hsize (FB_WIDTH), - .o_fb_vsize (FB_HEIGHT), - .o_fb_format (FB_FMT), - .o_fb_base (FB_BASE), - .o_fb_stride (FB_STRIDE), + .i_clk (clk_ihdmi), + .i_ce (ce_hpix), + .i_r (hr_out), + .i_g (hg_out), + .i_b (hb_out), + .i_hs (hhs_fix), + .i_vs (hvs_fix), + .i_fl (f1), + .i_de (hde_emu), + .iauto (1), + .himin (0), + .himax (0), + .vimin (0), + .vimax (0), - .avl_clk (clk_100m), - .avl_waitrequest (vbuf_waitrequest), - .avl_readdata (vbuf_readdata), - .avl_readdatavalid(vbuf_readdatavalid), - .avl_burstcount (vbuf_burstcount), - .avl_writedata (vbuf_writedata), - .avl_address (vbuf_address), - .avl_write (vbuf_write), - .avl_read (vbuf_read), - .avl_byteenable (vbuf_byteenable) -); + .o_clk (clk_hdmi), + .o_ce (scaler_out), + .o_r (hdmi_data[23:16]), + .o_g (hdmi_data[15:8]), + .o_b (hdmi_data[7:0]), + .o_hs (hdmi_hs), + .o_vs (hdmi_vs), + .o_de (hdmi_de), + .o_vbl (hdmi_vbl), + .o_brd (hdmi_brd), + .o_lltune (lltune), + .htotal (WIDTH + HFP + HBP + HS[11:0]), + .hsstart (WIDTH + HFP), + .hsend (WIDTH + HFP + HS[11:0]), + .hdisp (WIDTH), + .hmin (hmin), + .hmax (hmax), + .vtotal (HEIGHT + VFP + VBP + VS[11:0]), + .vsstart (HEIGHT + VFP), + .vsend (HEIGHT + VFP + VS[11:0]), + .vdisp (HEIGHT), + .vmin (vmin), + .vmax (vmax), + .vrr (vrr_mode), + .vrrmax (HEIGHT + VBP + VS[11:0] + 12'd1), + + .mode ({~lowlat,LFB_EN ? LFB_FLT : |scaler_flt,2'b00}), + .poly_clk (clk_sys), + .poly_a (coef_addr), + .poly_dw (coef_data), + .poly_wr (coef_wr), + + .pal1_clk (clk_pal), + .pal1_dw (pal_d), + .pal1_a (pal_a), + .pal1_wr (pal_wr), + + `ifdef MISTER_FB + `ifdef MISTER_FB_PALETTE + .pal2_clk (fb_pal_clk), + .pal2_dw (fb_pal_d), + .pal2_dr (fb_pal_q), + .pal2_a (fb_pal_a), + .pal2_wr (fb_pal_wr), + .pal_n (fb_en), + `endif + `endif + + .o_fb_ena (FB_EN), + .o_fb_hsize (FB_WIDTH), + .o_fb_vsize (FB_HEIGHT), + .o_fb_format (FB_FMT), + .o_fb_base (FB_BASE), + .o_fb_stride (FB_STRIDE), + + .avl_clk (clk_100m), + .avl_waitrequest (vbuf_waitrequest), + .avl_readdata (vbuf_readdata), + .avl_readdatavalid(vbuf_readdatavalid), + .avl_burstcount (vbuf_burstcount), + .avl_writedata (vbuf_writedata), + .avl_address (vbuf_address), + .avl_write (vbuf_write), + .avl_read (vbuf_read), + .avl_byteenable (vbuf_byteenable) + ); `endif reg LFB_EN = 0; @@ -811,8 +832,8 @@ always @(posedge clk_sys) begin end `ifdef MISTER_FB -reg fb_vbl; -always @(posedge clk_vid) fb_vbl <= hdmi_vbl; + reg fb_vbl; + always @(posedge clk_vid) fb_vbl <= hdmi_vbl; `endif reg ar_md_start; @@ -938,24 +959,24 @@ always @(posedge clk_vid) begin end `ifndef MISTER_DEBUG_NOHDMI -wire [15:0] lltune; -pll_hdmi_adj pll_hdmi_adj -( - .clk(FPGA_CLK1_50), - .reset_na(~reset_req), + wire [15:0] lltune; + pll_hdmi_adj pll_hdmi_adj + ( + .clk(FPGA_CLK1_50), + .reset_na(~reset_req), - .llena(lowlat), - .lltune({16{cfg_done}} & lltune), - .locked(led_locked), - .i_waitrequest(adj_waitrequest), - .i_write(adj_write), - .i_address(adj_address), - .i_writedata(adj_data), - .o_waitrequest(cfg_waitrequest), - .o_write(cfg_write), - .o_address(cfg_address), - .o_writedata(cfg_data) -); + .llena(lowlat), + .lltune({16{cfg_done}} & lltune), + .locked(led_locked), + .i_waitrequest(adj_waitrequest), + .i_write(adj_write), + .i_address(adj_address), + .i_writedata(adj_data), + .o_waitrequest(cfg_waitrequest), + .o_write(cfg_write), + .o_address(cfg_address), + .o_writedata(cfg_data) + ); `else assign led_locked = 0; `endif @@ -981,15 +1002,15 @@ end ///////////////////////// HDMI output ///////////////////////////////// `ifndef MISTER_DEBUG_NOHDMI -wire hdmi_clk_out; -pll_hdmi pll_hdmi -( - .refclk(FPGA_CLK1_50), - .rst(reset_req), - .reconfig_to_pll(reconfig_to_pll), - .reconfig_from_pll(reconfig_from_pll), - .outclk_0(hdmi_clk_out) -); + wire hdmi_clk_out; + pll_hdmi pll_hdmi + ( + .refclk(FPGA_CLK1_50), + .rst(reset_req), + .reconfig_to_pll(reconfig_to_pll), + .reconfig_from_pll(reconfig_from_pll), + .outclk_0(hdmi_clk_out) + ); `endif //1920x1080@60 PCLK=148.5MHz CEA @@ -1014,64 +1035,59 @@ reg [5:0] adj_address; reg [31:0] adj_data; `ifndef MISTER_DEBUG_NOHDMI -pll_cfg pll_cfg -( - .mgmt_clk(FPGA_CLK1_50), - .mgmt_reset(reset_req), - .mgmt_waitrequest(cfg_waitrequest), - .mgmt_read(0), - .mgmt_readdata(), - .mgmt_write(cfg_write), - .mgmt_address(cfg_address), - .mgmt_writedata(cfg_data), - .reconfig_to_pll(reconfig_to_pll), - .reconfig_from_pll(reconfig_from_pll) -); + pll_cfg_hdmi pll_cfg_hdmi + ( + .mgmt_clk(FPGA_CLK1_50), + .mgmt_reset(reset_req), + .mgmt_waitrequest(cfg_waitrequest), + .mgmt_write(cfg_write), + .mgmt_address(cfg_address), + .mgmt_writedata(cfg_data), + .reconfig_to_pll(reconfig_to_pll), + .reconfig_from_pll(reconfig_from_pll) + ); -reg cfg_got = 0; -always @(posedge clk_sys) begin - reg vsd, vsd2; - if(~cfg_ready || ~cfg_set) cfg_got <= cfg_set; - else begin - vsd <= HDMI_TX_VS; - vsd2 <= vsd; - if(~vsd2 & vsd) cfg_got <= cfg_set; - end -end - -reg cfg_ready = 0; -always @(posedge FPGA_CLK1_50) begin - reg gotd = 0, gotd2 = 0; - reg custd = 0, custd2 = 0; - reg old_wait = 0; - - gotd <= cfg_got; - gotd2 <= gotd; - - adj_write <= 0; - - custd <= cfg_custom_t; - custd2 <= custd; - if(custd2 != custd & ~gotd) begin - adj_address <= cfg_custom_p1; - adj_data <= cfg_custom_p2; - adj_write <= 1; + reg cfg_got = 0; + always @(posedge clk_sys) begin + reg vsd, vsd2; + if(~cfg_ready || ~cfg_set) cfg_got <= cfg_set; + else begin + vsd <= HDMI_TX_VS; + vsd2 <= vsd; + if(~vsd2 & vsd) cfg_got <= cfg_set; + end end - if(~gotd2 & gotd) begin - adj_address <= 2; - adj_data <= 0; - adj_write <= 1; + reg cfg_ready = 0; + always @(posedge FPGA_CLK1_50) begin + reg gotd = 0, gotd2 = 0; + reg custd = 0, custd2 = 0; + reg old_wait = 0; + + gotd <= cfg_got; + gotd2 <= gotd; + + adj_write <= 0; + + custd <= cfg_custom_t; + custd2 <= custd; + if(custd2 != custd & ~gotd) begin + adj_address <= cfg_custom_p1; + adj_data <= cfg_custom_p2; + adj_write <= 1; + end + + if(~gotd2 & gotd) begin + adj_address <= 2; + adj_data <= 0; + adj_write <= 1; + end + + old_wait <= adj_waitrequest; + if(old_wait & ~adj_waitrequest & gotd) cfg_ready <= 1; end - - old_wait <= adj_waitrequest; - if(old_wait & ~adj_waitrequest & gotd) cfg_ready <= 1; -end - `else - -wire cfg_ready = 1; - + wire cfg_ready = 1; `endif assign HDMI_I2C_SCL = hdmi_scl_en ? 1'b0 : 1'bZ; @@ -1087,72 +1103,71 @@ cyclonev_hps_interface_peripheral_i2c hdmi_i2c ); `ifndef MISTER_DEBUG_NOHDMI + `ifdef MISTER_FB + reg dis_output; + always @(posedge clk_hdmi) begin + reg dis; + dis <= fb_force_blank & ~LFB_EN; + dis_output <= dis; + end + `else + wire dis_output = 0; + `endif -`ifdef MISTER_FB -reg dis_output; -always @(posedge clk_hdmi) begin - reg dis; - dis <= fb_force_blank & ~LFB_EN; - dis_output <= dis; -end -`else -wire dis_output = 0; + wire [23:0] hdmi_data_mask; + wire hdmi_de_mask, hdmi_vs_mask, hdmi_hs_mask; + + reg [15:0] shadowmask_data; + reg shadowmask_wr = 0; + + shadowmask HDMI_shadowmask + ( + .clk(clk_hdmi), + .clk_sys(clk_sys), + + .cmd_wr(shadowmask_wr), + .cmd_in(shadowmask_data), + + .din(dis_output ? 24'd0 : hdmi_data), + .hs_in(hdmi_hs), + .vs_in(hdmi_vs), + .de_in(hdmi_de), + .brd_in(hdmi_brd), + .enable(~LFB_EN), + + .dout(hdmi_data_mask), + .hs_out(hdmi_hs_mask), + .vs_out(hdmi_vs_mask), + .de_out(hdmi_de_mask) + ); + + wire [23:0] hdmi_data_osd; + wire hdmi_de_osd, hdmi_vs_osd, hdmi_hs_osd; + + osd hdmi_osd + ( + .clk_sys(clk_sys), + + .io_osd(io_osd_hdmi), + .io_strobe(io_strobe), + .io_din(io_din), + + .clk_video(clk_hdmi), + .din(hdmi_data_mask), + .hs_in(hdmi_hs_mask), + .vs_in(hdmi_vs_mask), + .de_in(hdmi_de_mask), + + .dout(hdmi_data_osd), + .hs_out(hdmi_hs_osd), + .vs_out(hdmi_vs_osd), + .de_out(hdmi_de_osd) + ); + + wire hdmi_cs_osd; + csync csync_hdmi(clk_hdmi, hdmi_hs_osd, hdmi_vs_osd, hdmi_cs_osd); `endif -wire [23:0] hdmi_data_mask; -wire hdmi_de_mask, hdmi_vs_mask, hdmi_hs_mask; - -reg [15:0] shadowmask_data; -reg shadowmask_wr = 0; - -shadowmask HDMI_shadowmask -( - .clk(clk_hdmi), - .clk_sys(clk_sys), - - .cmd_wr(shadowmask_wr), - .cmd_in(shadowmask_data), - - .din(dis_output ? 24'd0 : hdmi_data), - .hs_in(hdmi_hs), - .vs_in(hdmi_vs), - .de_in(hdmi_de), - .brd_in(hdmi_brd), - .enable(~LFB_EN), - - .dout(hdmi_data_mask), - .hs_out(hdmi_hs_mask), - .vs_out(hdmi_vs_mask), - .de_out(hdmi_de_mask) -); - -wire [23:0] hdmi_data_osd; -wire hdmi_de_osd, hdmi_vs_osd, hdmi_hs_osd; - -osd hdmi_osd -( - .clk_sys(clk_sys), - - .io_osd(io_osd_hdmi), - .io_strobe(io_strobe), - .io_din(io_din), - - .clk_video(clk_hdmi), - .din(hdmi_data_mask), - .hs_in(hdmi_hs_mask), - .vs_in(hdmi_vs_mask), - .de_in(hdmi_de_mask), - - .dout(hdmi_data_osd), - .hs_out(hdmi_hs_osd), - .vs_out(hdmi_vs_osd), - .de_out(hdmi_de_osd) -); -`endif - -wire hdmi_cs_osd; -csync csync_hdmi(clk_hdmi, hdmi_hs_osd, hdmi_vs_osd, hdmi_cs_osd); - reg [23:0] dv_data; reg dv_hs, dv_vs, dv_de; wire [23:0] dv_data_osd; @@ -1185,11 +1200,12 @@ always @(posedge clk_vid) begin end dv_de1 <= !{hss,dv_hs_osd} && vde; - dv_hs1 <= csync_en ? dv_cs_osd : dv_hs_osd; - dv_vs1 <= dv_vs_osd; end dv_d1 <= dv_data_osd; + dv_hs1 <= csync_en ? dv_cs_osd : dv_hs_osd; + dv_vs1 <= dv_vs_osd; + dv_d2 <= dv_d1; dv_de2 <= dv_de1; dv_hs2 <= dv_hs1; @@ -1202,21 +1218,21 @@ always @(posedge clk_vid) begin end `ifndef MISTER_DISABLE_YC -assign {dv_data_osd, dv_hs_osd, dv_vs_osd, dv_cs_osd } = ~yc_en ? {vga_data_osd, vga_hs_osd, vga_vs_osd, vga_cs_osd } : {yc_o, yc_hs, yc_vs, yc_cs }; + assign {dv_data_osd, dv_hs_osd, dv_vs_osd, dv_cs_osd } = ~yc_en ? {vga_data_osd, vga_hs_osd, vga_vs_osd, vga_cs_osd } : {yc_o, yc_hs, yc_vs, yc_cs }; `else -assign {dv_data_osd, dv_hs_osd, dv_vs_osd, dv_cs_osd } = {vga_data_osd, vga_hs_osd, vga_vs_osd, vga_cs_osd }; + assign {dv_data_osd, dv_hs_osd, dv_vs_osd, dv_cs_osd } = {vga_data_osd, vga_hs_osd, vga_vs_osd, vga_cs_osd }; `endif wire hdmi_tx_clk; `ifndef MISTER_DEBUG_NOHDMI -cyclonev_clkselect hdmi_clk_sw -( - .clkselect({1'b1, ~vga_fb & direct_video}), - .inclk({clk_vid, hdmi_clk_out, 2'b00}), - .outclk(hdmi_tx_clk) -); + cyclonev_clkselect hdmi_clk_sw + ( + .clkselect({1'b1, ~vga_fb & direct_video}), + .inclk({clk_vid, hdmi_clk_out, 2'b00}), + .outclk(hdmi_tx_clk) + ); `else -assign hdmi_tx_clk = clk_vid; + assign hdmi_tx_clk = clk_vid; `endif altddio_out @@ -1261,10 +1277,17 @@ always @(posedge hdmi_tx_clk) begin hdmi_dv_vs <= dv_vs; hdmi_dv_de <= dv_de; +`ifndef MISTER_DEBUG_NOHDMI hs <= (~vga_fb & direct_video) ? hdmi_dv_hs : (direct_video & csync_en) ? hdmi_cs_osd : hdmi_hs_osd; vs <= (~vga_fb & direct_video) ? hdmi_dv_vs : hdmi_vs_osd; de <= (~vga_fb & direct_video) ? hdmi_dv_de : hdmi_de_osd; d <= (~vga_fb & direct_video) ? hdmi_dv_data : hdmi_data_osd; +`else + hs <= hdmi_dv_hs; + vs <= hdmi_dv_vs; + de <= hdmi_dv_de; + d <= hdmi_dv_data; +`endif hdmi_out_hs <= hs; hdmi_out_vs <= vs; @@ -1279,6 +1302,20 @@ assign HDMI_TX_D = hdmi_out_d; ///////////////////////// VGA output ////////////////////////////////// +`ifndef MISTER_DUAL_SDRAM + wire vga_tx_clk; + `ifndef MISTER_DEBUG_NOHDMI + cyclonev_clkselect vga_clk_sw + ( + .clkselect({1'b1, ~vga_fb & ~vga_scaler}), + .inclk({clk_vid, hdmi_clk_out, 2'b00}), + .outclk(vga_tx_clk) + ); + `else + assign vga_tx_clk = clk_vid; + `endif +`endif + wire [23:0] vga_data_sl; wire vga_de_sl, vga_ce_sl, vga_vs_sl, vga_hs_sl; scanlines #(0) VGA_scanlines @@ -1300,7 +1337,7 @@ scanlines #(0) VGA_scanlines ); wire [23:0] vga_data_osd; -wire vga_vs_osd, vga_hs_osd; +wire vga_vs_osd, vga_hs_osd, vga_de_osd; osd vga_osd ( .clk_sys(clk_sys), @@ -1318,46 +1355,13 @@ osd vga_osd .dout(vga_data_osd), .hs_out(vga_hs_osd), - .vs_out(vga_vs_osd) + .vs_out(vga_vs_osd), + .de_out(vga_de_osd) ); wire vga_cs_osd; csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd); -`ifndef MISTER_DUAL_SDRAM - wire VGA_DISABLE; - wire [23:0] vgas_o; - wire vgas_hs, vgas_vs, vgas_cs; - vga_out vga_scaler_out - ( - .clk(clk_hdmi), - .ypbpr_en(ypbpr_en), - .hsync(hdmi_hs_osd), - .vsync(hdmi_vs_osd), - .csync(hdmi_cs_osd), - .dout(vgas_o), - .din({24{hdmi_de_osd}} & hdmi_data_osd), - .hsync_o(vgas_hs), - .vsync_o(vgas_vs), - .csync_o(vgas_cs) - ); - - wire [23:0] vga_o, vga_o_t; - wire vga_hs, vga_vs, vga_cs, vga_hs_t, vga_vs_t, vga_cs_t; - vga_out vga_out - ( - .clk(clk_vid), - .ypbpr_en(ypbpr_en), - .hsync(vga_hs_osd), - .vsync(vga_vs_osd), - .csync(vga_cs_osd), - .dout(vga_o_t), - .din(vga_data_osd), - .hsync_o(vga_hs_t), - .vsync_o(vga_vs_t), - .csync_o(vga_cs_t) - ); - `ifndef MISTER_DISABLE_YC reg pal_en; reg yc_en; @@ -1365,7 +1369,7 @@ csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd); reg [16:0] ColorBurst_Range; reg [39:0] PhaseInc; wire [23:0] yc_o; - wire yc_hs, yc_vs, yc_cs; + wire yc_hs, yc_vs, yc_cs, yc_de; yc_out yc_out ( @@ -1377,25 +1381,78 @@ csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd); .hsync(vga_hs_osd), .vsync(vga_vs_osd), .csync(vga_cs_osd), + .de(vga_de_osd), .dout(yc_o), .din(vga_data_osd), .hsync_o(yc_hs), .vsync_o(yc_vs), - .csync_o(yc_cs) + .csync_o(yc_cs), + .de_o(yc_de) ); - - assign {vga_o, vga_hs, vga_vs, vga_cs } = ~yc_en ? {vga_o_t, vga_hs_t, vga_vs_t, vga_cs_t } : {yc_o, yc_hs, yc_vs, yc_cs }; -`else - assign {vga_o, vga_hs, vga_vs, vga_cs } = {vga_o_t, vga_hs_t, vga_vs_t, vga_cs_t } ; `endif - wire cs1 = (vga_fb | vga_scaler) ? vgas_cs : vga_cs; +`ifndef MISTER_DUAL_SDRAM + wire VGA_DISABLE; + wire [23:0] vgas_o; + wire vgas_hs, vgas_vs, vgas_cs, vgas_de; + `ifndef MISTER_DEBUG_NOHDMI + vga_out vga_scaler_out + ( + .clk(clk_hdmi), + .ypbpr_en(ypbpr_en), + .hsync(hdmi_hs_osd), + .vsync(hdmi_vs_osd), + .csync(hdmi_cs_osd), + .de(hdmi_de_osd), + .dout(vgas_o), + .din({24{hdmi_de_osd}} & hdmi_data_osd), + .hsync_o(vgas_hs), + .vsync_o(vgas_vs), + .csync_o(vgas_cs), + .de_o(vgas_de) + ); + `else + assign {vgas_o, vgas_hs, vgas_vs, vgas_cs, vgas_de} = 0; + `endif - assign VGA_VS = (VGA_EN | SW[3]) ? 1'bZ : (((vga_fb | vga_scaler) ? (~vgas_vs ^ VS[12]) : VGA_DISABLE ? 1'd1 : ~vga_vs) | csync_en); - assign VGA_HS = (VGA_EN | SW[3]) ? 1'bZ : ((vga_fb | vga_scaler) ? ((csync_en ? ~vgas_cs : ~vgas_hs) ^ HS[12]) : VGA_DISABLE ? 1'd1 : (csync_en ? ~vga_cs : ~vga_hs)); - assign VGA_R = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[23:18] : VGA_DISABLE ? 6'd0 : vga_o[23:18]; - assign VGA_G = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[15:10] : VGA_DISABLE ? 6'd0 : vga_o[15:10]; - assign VGA_B = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[7:2] : VGA_DISABLE ? 6'd0 : vga_o[7:2] ; + wire [23:0] vga_o, vga_o_t; + wire vga_hs, vga_vs, vga_cs, vga_de, vga_hs_t, vga_vs_t, vga_cs_t, vga_de_t; + vga_out vga_out + ( + .clk(clk_vid), + .ypbpr_en(ypbpr_en), + .hsync(vga_hs_osd), + .vsync(vga_vs_osd), + .csync(vga_cs_osd), + .de(vga_de_osd), + .dout(vga_o_t), + .din(vga_data_osd), + .hsync_o(vga_hs_t), + .vsync_o(vga_vs_t), + .csync_o(vga_cs_t), + .de_o(vga_de_t) + ); + + `ifndef MISTER_DISABLE_YC + assign {vga_o, vga_hs, vga_vs, vga_cs, vga_de } = ~yc_en ? {vga_o_t, vga_hs_t, vga_vs_t, vga_cs_t, vga_de_t } : {yc_o, yc_hs, yc_vs, yc_cs, yc_de }; + `else + assign {vga_o, vga_hs, vga_vs, vga_cs, vga_de } = {vga_o_t, vga_hs_t, vga_vs_t, vga_cs_t, vga_de_t } ; + `endif + + wire vgas_en = vga_fb | vga_scaler; + + wire cs1 = vgas_en ? vgas_cs : vga_cs; + wire de1 = vgas_en ? vgas_de : vga_de; + + assign VGA_VS = av_dis ? 1'bZ : ((vgas_en ? (~vgas_vs ^ VS[12]) : VGA_DISABLE ? 1'd1 : ~vga_vs) | csync_en); + assign VGA_HS = av_dis ? 1'bZ : (vgas_en ? ((csync_en ? ~vgas_cs : ~vgas_hs) ^ HS[12]) : VGA_DISABLE ? 1'd1 : (csync_en ? ~vga_cs : ~vga_hs)); + assign VGA_R = av_dis ? 6'bZZZZZZ : vgas_en ? vgas_o[23:18] : VGA_DISABLE ? 6'd0 : vga_o[23:18]; + assign VGA_G = av_dis ? 6'bZZZZZZ : vgas_en ? vgas_o[15:10] : VGA_DISABLE ? 6'd0 : vga_o[15:10]; + assign VGA_B = av_dis ? 6'bZZZZZZ : vgas_en ? vgas_o[7:2] : VGA_DISABLE ? 6'd0 : vga_o[7:2] ; + + wire [1:0] vga_r = vgas_en ? vgas_o[17:16] : VGA_DISABLE ? 2'd0 : vga_o[17:16]; + wire [1:0] vga_g = vgas_en ? vgas_o[9:8] : VGA_DISABLE ? 2'd0 : vga_o[9:8]; + wire [1:0] vga_b = vgas_en ? vgas_o[1:0] : VGA_DISABLE ? 2'd0 : vga_o[1:0]; `endif reg video_sync = 0; @@ -1425,14 +1482,14 @@ end ///////////////////////// Audio output //////////////////////////////// -assign SDCD_SPDIF =(SW[3] & ~spdif) ? 1'b0 : 1'bZ; +assign SDCD_SPDIF = (mcp_en & ~spdif) ? 1'b0 : 1'bZ; `ifndef MISTER_DUAL_SDRAM wire analog_l, analog_r; - assign AUDIO_SPDIF = SW[3] ? 1'bZ : SW[0] ? HDMI_LRCLK : spdif; - assign AUDIO_R = SW[3] ? 1'bZ : SW[0] ? HDMI_I2S : analog_r; - assign AUDIO_L = SW[3] ? 1'bZ : SW[0] ? HDMI_SCLK : analog_l; + assign AUDIO_SPDIF = av_dis ? 1'bZ : (SW[0] | mcp_en) ? HDMI_LRCLK : spdif; + assign AUDIO_R = av_dis ? 1'bZ : (SW[0] | mcp_en) ? HDMI_I2S : analog_r; + assign AUDIO_L = av_dis ? 1'bZ : (SW[0] | mcp_en) ? HDMI_SCLK : analog_l; `endif assign HDMI_MCLK = clk_audio; @@ -1485,43 +1542,43 @@ audio_out audio_out `ifndef MISTER_DISABLE_ALSA -wire aspi_sck,aspi_mosi,aspi_ss,aspi_miso; -cyclonev_hps_interface_peripheral_spi_master spi -( - .sclk_out(aspi_sck), - .txd(aspi_mosi), // mosi - .rxd(aspi_miso), // miso + wire aspi_sck,aspi_mosi,aspi_ss,aspi_miso; + cyclonev_hps_interface_peripheral_spi_master spi + ( + .sclk_out(aspi_sck), + .txd(aspi_mosi), // mosi + .rxd(aspi_miso), // miso - .ss_0_n(aspi_ss), - .ss_in_n(1) -); + .ss_0_n(aspi_ss), + .ss_in_n(1) + ); -wire [28:0] alsa_address; -wire [63:0] alsa_readdata; -wire alsa_ready; -wire alsa_req; -wire alsa_late; + wire [28:0] alsa_address; + wire [63:0] alsa_readdata; + wire alsa_ready; + wire alsa_req; + wire alsa_late; -wire [15:0] alsa_l, alsa_r; + wire [15:0] alsa_l, alsa_r; -alsa alsa -( - .reset(reset), - .clk(clk_audio), + alsa alsa + ( + .reset(reset), + .clk(clk_audio), - .ram_address(alsa_address), - .ram_data(alsa_readdata), - .ram_req(alsa_req), - .ram_ready(alsa_ready), + .ram_address(alsa_address), + .ram_data(alsa_readdata), + .ram_req(alsa_req), + .ram_ready(alsa_ready), - .spi_ss(aspi_ss), - .spi_sck(aspi_sck), - .spi_mosi(aspi_mosi), - .spi_miso(aspi_miso), + .spi_ss(aspi_ss), + .spi_sck(aspi_sck), + .spi_mosi(aspi_mosi), + .spi_miso(aspi_miso), - .pcm_l(alsa_l), - .pcm_r(alsa_r) -); + .pcm_l(alsa_l), + .pcm_r(alsa_r) + ); `endif //////////////// User I/O (USB 3.0 connector) ///////////////////////// @@ -1722,7 +1779,7 @@ emu emu .SDRAM2_nRAS(SDRAM2_nRAS), .SDRAM2_nCAS(SDRAM2_nCAS), .SDRAM2_CLK(SDRAM2_CLK), - .SDRAM2_EN(SW[3]), + .SDRAM2_EN(io_dig), `endif .BUTTONS(btn), @@ -1732,11 +1789,7 @@ emu emu .SD_MOSI(SD_MOSI), .SD_MISO(SD_MISO), .SD_CS(SD_CS), -`ifdef MISTER_DUAL_SDRAM - .SD_CD(mcp_sdcd), -`else - .SD_CD(mcp_sdcd & (SW[0] ? VGA_HS : (SW[3] | SDCD_SPDIF))), -`endif + .SD_CD(SD_CD), .UART_CTS(uart_rts), .UART_RTS(uart_cts), @@ -1765,19 +1818,17 @@ assign sync_out = sync_in ^ pol; reg pol; always @(posedge clk) begin - integer pos = 0, neg = 0, cnt = 0; + reg [31:0] cnt; reg s1,s2; s1 <= sync_in; s2 <= s1; + cnt <= s2 ? (cnt - 1) : (cnt + 1); - if(~s2 & s1) neg <= cnt; - if(s2 & ~s1) pos <= cnt; - - cnt <= cnt + 1; - if(s2 != s1) cnt <= 0; - - pol <= pos > neg; + if(~s2 & s1) begin + cnt <= 0; + pol <= cnt[31]; + end end endmodule diff --git a/sys/vga_out.sv b/sys/vga_out.sv index fe8172b..4160635 100644 --- a/sys/vga_out.sv +++ b/sys/vga_out.sv @@ -7,23 +7,27 @@ module vga_out input hsync, input vsync, input csync, + input de, input [23:0] din, output [23:0] dout, output reg hsync_o, output reg vsync_o, - output reg csync_o + output reg csync_o, + output reg de_o ); -wire [5:0] red = din[23:18]; -wire [5:0] green = din[15:10]; -wire [5:0] blue = din[7:2]; +wire [7:0] red = din[23:16]; +wire [7:0] green = din[15:8]; +wire [7:0] blue = din[7:0]; // http://marsee101.blog19.fc2.com/blog-entry-2311.html -// Y = 16 + 0.257*R + 0.504*G + 0.098*B (Y = 0.299*R + 0.587*G + 0.114*B) -// Pb = 128 - 0.148*R - 0.291*G + 0.439*B (Pb = -0.169*R - 0.331*G + 0.500*B) -// Pr = 128 + 0.439*R - 0.368*G - 0.071*B (Pr = 0.500*R - 0.419*G - 0.081*B) + + +// Y = 0.301*R + 0.586*G + 0.113*B (Y = 0.299*R + 0.587*G + 0.114*B) +// Pb = 128 - 0.168*R - 0.332*G + 0.500*B (Pb = -0.169*R - 0.331*G + 0.500*B) +// Pr = 128 + 0.500*R - 0.418*G - 0.082*B (Pr = 0.500*R - 0.419*G - 0.081*B) reg [7:0] y, pb, pr; reg [23:0] rgb; @@ -33,32 +37,33 @@ always @(posedge clk) begin reg [18:0] y_1b, pb_1b, pr_1b; reg [18:0] y_2, pb_2, pr_2; reg [23:0] din1, din2; - reg hsync2, vsync2, csync2; - reg hsync1, vsync1, csync1; + reg hsync2, vsync2, csync2, de2; + reg hsync1, vsync1, csync1, de1; - y_1r <= 19'd04096 + ({red, 8'd0} + {red, 3'd0}); - pb_1r <= 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}); - pr_1r <= 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}); + y_1r <= {red, 6'd0} + {red, 3'd0} + {red, 2'd0} + red; + pb_1r <= 19'd32768 - ({red, 5'd0} + {red, 3'd0} + {red, 1'd0}); + pr_1r <= 19'd32768 + {red, 7'd0}; - y_1g <= {green, 9'd0} + {green, 2'd0}; - pb_1g <= {green, 8'd0} + {green, 5'd0} + {green, 3'd0}; - pr_1g <= {green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}; + y_1g <= {green, 7'd0} + {green, 4'd0} + {green, 2'd0} + {green, 1'd0}; + pb_1g <= {green, 6'd0} + {green, 4'd0} + {green, 2'd0} + green; + pr_1g <= {green, 6'd0} + {green, 5'd0} + {green, 3'd0} + {green, 1'd0}; - y_1b <= {blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0}; - pb_1b <= {blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0}; - pr_1b <= {blue, 6'd0} + {blue, 3'd0}; + y_1b <= {blue, 4'd0} + {blue, 3'd0} + {blue, 2'd0} + blue; + pb_1b <= {blue, 7'd0}; + pr_1b <= {blue, 4'd0} + {blue, 2'd0} + blue; y_2 <= y_1r + y_1g + y_1b; pb_2 <= pb_1r - pb_1g + pb_1b; pr_2 <= pr_1r - pr_1g - pr_1b; - y <= ( y_2[18] || !y_2[17:12]) ? 8'd16 : (y_2[17:8] > 235) ? 8'd235 : y_2[15:8]; - pb <= (pb_2[18] || !pb_2[17:12]) ? 8'd16 : (&pb_2[17:12]) ? 8'd240 : pb_2[15:8]; - pr <= (pr_2[18] || !pr_2[17:12]) ? 8'd16 : (&pr_2[17:12]) ? 8'd240 : pr_2[15:8]; + y <= y_2[18] ? 8'd0 : y_2[16] ? 8'd255 : y_2[15:8]; + pb <= pb_2[18] ? 8'd0 : pb_2[16] ? 8'd255 : pb_2[15:8]; + pr <= pr_2[18] ? 8'd0 : pr_2[16] ? 8'd255 : pr_2[15:8]; hsync_o <= hsync2; hsync2 <= hsync1; hsync1 <= hsync; vsync_o <= vsync2; vsync2 <= vsync1; vsync1 <= vsync; csync_o <= csync2; csync2 <= csync1; csync1 <= csync; + de_o <= de2; de2 <= de1; de1 <= de; rgb <= din2; din2 <= din1; din1 <= din; end diff --git a/sys/video_freak.sv b/sys/video_freak.sv index 18beb03..65375cd 100644 --- a/sys/video_freak.sv +++ b/sys/video_freak.sv @@ -170,10 +170,8 @@ reg [11:0] mul_arg1, mul_arg2; wire [23:0] mul_res; sys_umul #(12,12) mul(CLK_VIDEO,mul_start,mul_run, mul_arg1,mul_arg2,mul_res); -wire [11:0] wideres = mul_res[11:0] + hsize; - always @(posedge CLK_VIDEO) begin - reg [11:0] oheight,wres; + reg [11:0] oheight,htarget,wres,hinteger,wideres; reg [12:0] arxf,aryf; reg [3:0] cnt; reg narrow; @@ -188,11 +186,18 @@ always @(posedge CLK_VIDEO) begin else if(~div_start & ~div_run & ~mul_start & ~mul_run) begin cnt <= cnt + 1'd1; case(cnt) + // example ideal and non-ideal cases: + // [1] 720x400 4:3 VGA 80x25 text-mode (non-square pixels) + // [2] 640x480 4:3 VGA graphics mode (square pixels) + // [3] 512x512 4:3 X68000 graphics mode (non-square pixels) 0: begin div_num <= HDMI_HEIGHT; div_den <= vsize; div_start <= 1; end + // [1] 1080 / 400 -> 2 + // [2] 1080 / 480 -> 2 + // [3] 1080 / 512 -> 2 1: if(!div_res[11:0]) begin // screen resolution is lower than video resolution. @@ -206,6 +211,9 @@ always @(posedge CLK_VIDEO) begin mul_arg2 <= div_res[11:0]; mul_start <= 1; end + // [1] 1080 / 400 * 400 -> 800 + // [2] 1080 / 480 * 480 -> 960 + // [3] 1080 / 512 * 512 -> 1024 2: begin oheight <= mul_res[11:0]; @@ -219,27 +227,43 @@ always @(posedge CLK_VIDEO) begin mul_arg2 <= arx_i; mul_start <= 1; end + // [1] 1080 / 400 * 400 * 4 -> 3200 + // [2] 1080 / 480 * 480 * 4 -> 3840 + // [3] 1080 / 512 * 512 * 4 -> 4096 4: begin div_num <= mul_res; div_den <= ary_i; div_start <= 1; end + // [1] 1080 / 480 * 480 * 4 / 3 -> 1066 + // [2] 1080 / 480 * 480 * 4 / 3 -> 1280 + // [3] 1080 / 512 * 512 * 4 / 3 -> 1365 + // saved as htarget 5: begin + htarget <= div_res[11:0]; div_num <= div_res; div_den <= hsize; div_start <= 1; end + // computes wide scaling factor as a ceiling division + // [1] 1080 / 400 * 400 * 4 / 3 / 720 -> 1 + // [2] 1080 / 480 * 480 * 4 / 3 / 640 -> 2 + // [3] 1080 / 512 * 512 * 4 / 3 / 512 -> 2 6: begin mul_arg1 <= hsize; mul_arg2 <= div_res[11:0] ? div_res[11:0] : 12'd1; mul_start <= 1; end + // [1] 1080 / 400 * 400 * 4 / 3 / 720 * 720 -> 720 + // [2] 1080 / 480 * 480 * 4 / 3 / 640 * 640 -> 1280 + // [3] 1080 / 512 * 512 * 4 / 3 / 512 * 512 -> 1024 7: if(mul_res <= HDMI_WIDTH) begin - cnt <= 10; + hinteger = mul_res[11:0]; + cnt <= 12; end 8: begin @@ -247,23 +271,50 @@ always @(posedge CLK_VIDEO) begin div_den <= hsize; div_start <= 1; end + // [1] 1920 / 720 -> 2 + // [2] 1920 / 640 -> 3 + // [3] 1920 / 512 -> 3 9: begin mul_arg1 <= hsize; mul_arg2 <= div_res[11:0] ? div_res[11:0] : 12'd1; mul_start <= 1; end + // [1] 1920 / 720 * 720 -> 1440 + // [2] 1920 / 640 * 640 -> 1920 + // [3] 1920 / 512 * 512 -> 1536 - 10: begin - narrow <= ((div_num[11:0] - mul_res[11:0]) <= (wideres - div_num[11:0])) || (wideres > HDMI_WIDTH); - wres <= wideres; + 10: begin + hinteger <= mul_res[11:0]; + mul_arg1 <= vsize; + mul_arg2 <= div_res[11:0] ? div_res[11:0] : 12'd1; + mul_start <= 1; + end + + 11: begin + oheight <= mul_res[11:0]; + end + + 12: begin + wideres <= hinteger + hsize; + narrow <= ((htarget - hinteger) <= (wideres - htarget)) || (wideres > HDMI_WIDTH); + wres <= hinteger == htarget ? hinteger : wideres; end + // [1] 1066 - 720 = 346 <= 1440 - 1066 = 374 || 1440 > 1920 -> true + // [2] 1280 - 1280 = 0 <= 1920 - 1280 = 640 || 1920 > 1920 -> true + // [3] 1365 - 1024 = 341 <= 1536 - 1365 = 171 || 1536 > 1920 -> false + // 1. narrow flag is true when mul_res[11:0] narrow width is closer to + // htarget aspect ratio target width or when wideres wider width + // does not fit to the screen. + // 2. wres becomes wideres only when mul_res[11:0] narrow width not equal + // to target width, meaning it is not optimal for source aspect ratio. + // otherwise it is set to narrow width that is optimal. - 11: begin + 13: begin case(SCALE) - 2: arxf <= {1'b1, mul_res[11:0]}; - 3: arxf <= {1'b1, (wres > HDMI_WIDTH) ? mul_res[11:0] : wres}; - 4: arxf <= {1'b1, narrow ? mul_res[11:0] : wres}; + 2: arxf <= {1'b1, hinteger}; + 3: arxf <= {1'b1, (wres > HDMI_WIDTH) ? hinteger : wres}; + 4: arxf <= {1'b1, narrow ? hinteger : wres}; default: arxf <= {1'b1, div_num[11:0]}; endcase aryf <= {1'b1, oheight}; diff --git a/sys/yc_out.sv b/sys/yc_out.sv index 2e9a24e..984fc37 100644 --- a/sys/yc_out.sv +++ b/sys/yc_out.sv @@ -36,13 +36,15 @@ module yc_out input hsync, input vsync, input csync, + input de, input [23:0] din, output [23:0] dout, output reg hsync_o, output reg vsync_o, - output reg csync_o + output reg csync_o, + output reg de_o ); wire [7:0] red = din[23:16]; @@ -61,6 +63,7 @@ typedef struct { logic hsync; logic vsync; logic csync; + logic de; } phase_t; localparam MAX_PHASES = 7'd8; @@ -211,11 +214,11 @@ always_ff @(posedge clk) begin end // Adjust sync timing correctly - phase[1].hsync <= hsync; phase[1].vsync <= vsync; phase[1].csync <= csync; - phase[2].hsync <= phase[1].hsync; phase[2].vsync <= phase[1].vsync; phase[2].csync <= phase[1].csync; - phase[3].hsync <= phase[2].hsync; phase[3].vsync <= phase[2].vsync; phase[3].csync <= phase[2].csync; - phase[4].hsync <= phase[3].hsync; phase[4].vsync <= phase[3].vsync; phase[4].csync <= phase[3].csync; - hsync_o <= phase[4].hsync; vsync_o <= phase[4].vsync; csync_o <= phase[4].csync; + phase[1].hsync <= hsync; phase[1].vsync <= vsync; phase[1].csync <= csync; phase[1].de <= de; + phase[2].hsync <= phase[1].hsync; phase[2].vsync <= phase[1].vsync; phase[2].csync <= phase[1].csync; phase[2].de <= phase[1].de; + phase[3].hsync <= phase[2].hsync; phase[3].vsync <= phase[2].vsync; phase[3].csync <= phase[2].csync; phase[3].de <= phase[2].de; + phase[4].hsync <= phase[3].hsync; phase[4].vsync <= phase[3].vsync; phase[4].csync <= phase[3].csync; phase[4].de <= phase[3].de; + hsync_o <= phase[4].hsync; vsync_o <= phase[4].vsync; csync_o <= phase[4].csync; de_o <= phase[4].de; phase[1].y <= phase[0].y; phase[2].y <= phase[1].y; phase[3].y <= phase[2].y; phase[4].y <= phase[3].y; phase[5].y <= phase[4].y;