├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── README.md ├── docs ├── gaussian_divide.m ├── greyscale.m ├── images │ ├── cam_diagram.jpg │ ├── gaussian.jpg │ ├── kerneltop_diagram.jpg │ ├── kp_top.jpg │ ├── preprocess_diagram.jpg │ ├── sobel.jpg │ ├── sobelDemo.jpg │ ├── sys_top.jpg │ └── top_diagram.jpg ├── notes.txt └── sccb_notes.txt ├── ip └── clk_wiz_0 │ ├── clk_wiz_0.dcp │ ├── clk_wiz_0.v │ ├── clk_wiz_0.veo │ ├── clk_wiz_0.xci │ ├── clk_wiz_0.xdc │ ├── clk_wiz_0.xml │ ├── clk_wiz_0_board.xdc │ ├── clk_wiz_0_clk_wiz.v │ ├── clk_wiz_0_ooc.xdc │ ├── clk_wiz_0_sim_netlist.v │ ├── clk_wiz_0_sim_netlist.vhdl │ ├── clk_wiz_0_stub.v │ ├── clk_wiz_0_stub.vhdl │ ├── doc │ └── clk_wiz_v6_0_changelog.txt │ ├── mmcm_pll_drp_func_7s_mmcm.vh │ ├── mmcm_pll_drp_func_7s_pll.vh │ ├── mmcm_pll_drp_func_us_mmcm.vh │ ├── mmcm_pll_drp_func_us_pll.vh │ ├── mmcm_pll_drp_func_us_plus_mmcm.vh │ └── mmcm_pll_drp_func_us_plus_pll.vh ├── rtl ├── HDMI_TMDS.v ├── HDMI_encode.v ├── HDMI_out.v ├── HDMI_top.v ├── cam_capture.v ├── cam_top.v ├── cfg_i2c_master.v ├── cfg_interface.v ├── cfg_rom.v ├── debounce.v ├── display_interface.v ├── fifo_async.v ├── fifo_sync.v ├── mem_bram.v ├── mem_interface.v ├── pp_greyscale.v ├── pp_preprocess.v ├── ps_gaussian.v ├── ps_gaussian_top.v ├── ps_kernel_control.v ├── ps_linebuffer.v ├── ps_sobel.v ├── ps_sobel_top.v ├── sys_control.v ├── sys_top.v └── vtc.v ├── tb ├── camera_config_tb.v ├── capture_tb.sv ├── display_interface_tb.sv ├── gtkwave │ └── camera_config.gtkw ├── linebuffer_tb.sv ├── mem_interface_tb.sv ├── mountain_bmp.bmp ├── pp_preprocess_tb.sv ├── ps_kernel_control_tb.sv ├── tb.sv └── vtc_tb.v └── test.xdc /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.drawio 3 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "g++.exe - Build and debug active file", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "${fileDirname}\\${fileBasenameNoExtension}.exe", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${fileDirname}", 15 | "environment": [], 16 | "externalConsole": false, 17 | "MIMode": "gdb", 18 | "miDebuggerPath": "C:\\msys64\\mingw64\\bin\\gdb.exe", 19 | "setupCommands": [ 20 | { 21 | "description": "Enable pretty-printing for gdb", 22 | "text": "-enable-pretty-printing", 23 | "ignoreFailures": true 24 | } 25 | ], 26 | "preLaunchTask": "C/C++: g++.exe build active file" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "type": "cppbuild", 5 | "label": "C/C++: g++.exe build active file", 6 | "command": "C:\\TDM-GCC-64\\bin\\g++.exe", 7 | "args": [ 8 | "-g", 9 | "${file}", 10 | "-o", 11 | "${fileDirname}\\${fileBasenameNoExtension}.exe" 12 | ], 13 | "options": { 14 | "cwd": "${fileDirname}" 15 | }, 16 | "problemMatcher": [ 17 | "$gcc" 18 | ], 19 | "group": { 20 | "kind": "build", 21 | "isDefault": true 22 | }, 23 | "detail": "Task generated by Debugger." 24 | } 25 | ], 26 | "version": "2.0.0" 27 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Video Filtering on Artix-7 FPGA 2 | 3 | ![](docs/images/sobelDemo.jpg) 4 | 5 | __Description:__ 6 | 7 | This project implements a video processing pipeline that captures video data from an OV7670 camera and applies a Gaussian lowpass filter and a Sobel edge detection filter. 8 | 9 | Users can use the buttons and switches on the dev board to interact with the video processing system. 10 | - Video processing can be toggled on and off (video passthrough) 11 | - Gaussian and Sobel filters can be enabled or disabled seperately 12 | - Sobel filter thresholding can be changed by using the board buttons. 13 | 14 | The project is completed; more documentation to come when I have time. 15 | 16 | __High-level Overview:__ 17 | ![](docs/images/top_diagram.jpg) 18 | - The system is comprised of a camera interface block, preprocessing block, and gaussian and sobel filtering blocks. 19 | - Processed video data is stored into a framebuffer synthesized as block memory where it is retrieved for display over HDMI. 20 | - In RGB video passthrough mode, pixels are represented in RGB444 format and extended to RGB888 for TMDS encoding. 21 | - In video processing modes, pixels are represented as eight-bit greyscale values. 22 | - Display format is 640x480 30FPS. 23 | 24 | __Camera Interface:__ 25 | ![](docs/images/cam_diagram.jpg) 26 | - The camera interface configures the OV7670 camera via i2c and captures pixel data (RGB444) into an asynchronous FIFO. 27 | 28 | __Preprocessing (RGB to Greyscale):__ 29 | ![](docs/images/preprocess_diagram.jpg) 30 | - The preprocessing block converts RGB444 to greyscale for filtering. It uses the algorithm ```y = 0.299*R + 0.587*G + 0.114*B```. 31 | - The algorithm is implemented using bit-shifts, see ```docs/notes.txt```. 32 | 33 | __Kernel Processing:__ 34 | ![](docs/images/kerneltop_diagram.jpg) 35 | Both the Gaussian and Sobel filters are implemented using the designs shown above. 36 | - A kernel control module (ps_kernel_control) fetches data from the FIFO of the previous stage in the 37 | system pipeline and fills the line buffers sequentially. 38 | - Once three line buffers are full, it begins to feed pixel data 9 pixels at a time (3 from each line) 39 | to the kernel processing pipeline. 40 | - The output from the kernel processing pipeline is written to a synchronous FIFO. 41 | 42 | Gaussian: 43 | ![](docs/images/gaussian.jpg) 44 | 45 | Sobel: 46 | ![](docs/images/sobel.jpg) 47 | Some noteworthy design features: 48 | - Technically, the Sobel operator is expressed as ```G = sqrt(Gx^2 + Gy^2)``` . 49 | - To avoid doing the square root (doable, but would need a CORDIC), thresholding is used instead. 50 | 51 | __Demos__ 52 | - Click the images below to view Youtube videos. 53 | [![Gaussian Filter](https://img.youtube.com/vi/dFgFBZIkOFI/0.jpg)](https://www.youtube.com/watch?v=dFgFBZIkOFI) 54 | [![Full Demo](https://img.youtube.com/vi/nitLR1SwYG0/0.jpg)](https://www.youtube.com/watch?v=nitLR1SwYG0) 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/gaussian_divide.m: -------------------------------------------------------------------------------- 1 | error = []; 2 | x = []; 3 | 4 | for i = 1:2048 5 | x(i) = i; 6 | index = uint32(i); 7 | 8 | shiftResult = bitsra(index,4); 9 | refResult = index/16; 10 | 11 | error(i) = abs((shiftResult-refResult)/refResult)*100; 12 | 13 | end 14 | 15 | figure('Name', 'Error'); 16 | plot(x, error); 17 | -------------------------------------------------------------------------------- /docs/greyscale.m: -------------------------------------------------------------------------------- 1 | 2 | r_error = []; 3 | g_error = []; 4 | b_error = []; 5 | x = []; 6 | 7 | % decimal 16 - 240 8 | for i = 16:240 9 | x(i) = i; 10 | 11 | r = uint8(i); 12 | g = uint8(i); 13 | b = uint8(i); 14 | 15 | g_r = bitsra(r,2) + bitsra(r,5) + bitsra(r,6); 16 | g_g = bitsra(g,1) + bitsra(g,4) + bitsra(g,5); 17 | g_b = bitsra(b,3); 18 | 19 | r_ref = i; 20 | g_ref = i; 21 | b_ref = i; 22 | 23 | g_r_ref = 0.299*r_ref; 24 | g_g_ref = 0.587*g_ref; 25 | g_b_ref = 0.114*b_ref; 26 | 27 | r_error(i) = abs((g_r - g_r_ref)/ g_r_ref) * 100; 28 | g_error(i) = abs((g_g - g_g_ref)/ g_g_ref) * 100; 29 | b_error(i) = abs((g_b - g_b_ref)/ g_b_ref) * 100; 30 | end 31 | 32 | figure('Name', 'Red Error'); 33 | plot(x, r_error); 34 | 35 | figure('Name', 'Green Error'); 36 | plot(x, g_error); 37 | 38 | figure('Name', 'Blue Error'); 39 | plot(x, b_error); -------------------------------------------------------------------------------- /docs/images/cam_diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgeyhere/FPGA-Video-Processing/cea80bafc0d6f4e5dbbade748fdbe276a026a60c/docs/images/cam_diagram.jpg -------------------------------------------------------------------------------- /docs/images/gaussian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgeyhere/FPGA-Video-Processing/cea80bafc0d6f4e5dbbade748fdbe276a026a60c/docs/images/gaussian.jpg -------------------------------------------------------------------------------- /docs/images/kerneltop_diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgeyhere/FPGA-Video-Processing/cea80bafc0d6f4e5dbbade748fdbe276a026a60c/docs/images/kerneltop_diagram.jpg -------------------------------------------------------------------------------- /docs/images/kp_top.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgeyhere/FPGA-Video-Processing/cea80bafc0d6f4e5dbbade748fdbe276a026a60c/docs/images/kp_top.jpg -------------------------------------------------------------------------------- /docs/images/preprocess_diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgeyhere/FPGA-Video-Processing/cea80bafc0d6f4e5dbbade748fdbe276a026a60c/docs/images/preprocess_diagram.jpg -------------------------------------------------------------------------------- /docs/images/sobel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgeyhere/FPGA-Video-Processing/cea80bafc0d6f4e5dbbade748fdbe276a026a60c/docs/images/sobel.jpg -------------------------------------------------------------------------------- /docs/images/sobelDemo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgeyhere/FPGA-Video-Processing/cea80bafc0d6f4e5dbbade748fdbe276a026a60c/docs/images/sobelDemo.jpg -------------------------------------------------------------------------------- /docs/images/sys_top.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgeyhere/FPGA-Video-Processing/cea80bafc0d6f4e5dbbade748fdbe276a026a60c/docs/images/sys_top.jpg -------------------------------------------------------------------------------- /docs/images/top_diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgeyhere/FPGA-Video-Processing/cea80bafc0d6f4e5dbbade748fdbe276a026a60c/docs/images/top_diagram.jpg -------------------------------------------------------------------------------- /docs/notes.txt: -------------------------------------------------------------------------------- 1 | Goal: 2 | Do edge detection on OV7670 video stream. 3 | 4 | /////////////////////////////////////////////// 5 | Intermediate Goal 3: 6 | -> Implement a reconfigurable kernel processor (KP) that applies 7 | a kernel to the greyscale video stream prior to frame buffer. 8 | 9 | - KP should be parameterized. 10 | - Users should be able to specify kernel size. 11 | - Users should be able to specify kernel constants. 12 | - Users should be able to specify the video resolution. 13 | 14 | - KP should have an enable input such that the unaltered 15 | video stream is passed through. 16 | 17 | Need to find out what the fmax of system currently is in order 18 | to optimize KP. 19 | 20 | Higher frequency -> more pipeline stages -> higher cycles per op 21 | vs 22 | Lower frequency -> fewer pipeline stages -> fewer cycles per op 23 | 24 | 25 | 26 | /////////////////////////////////////////////// 27 | Intermediate Goal 2: 28 | -> Implement a preprocessor that converts RGB444 to grayscale 29 | prior to framebuffer 30 | 31 | -> Add functionality to camera configuration module: 32 | - when in greyscale mode, use RGB565 33 | - when in color mode, use RGB444 34 | 35 | 36 | Grayscale Algorithm: 37 | - luminosity method 38 | 39 | y = 0.299R + 0.587G + 0.114B 40 | 41 | Potential Approaches: 42 | 43 | 1) Use 32-bit single precision fixed-point arithmetic, 44 | then truncate the result for the 12-bit framebuffer. 45 | 46 | 2) Change the form of the algorithm to: 47 | y = (299/100)*R + (587/100)*G + (114/100)*B 48 | 49 | 3) Use bit shifts to get close to the constants. 50 | y = [ (R>>2) + (R>>5) + (R>>6) ] + [ (G>>1) + (G>>4) + (G>>5)] + [ (B>>3) ] 51 | y = [ 0.25R + 0.03R + 0.01R ] + [ 0.5G + 0.06G + 0.03G ] + [ 0.12B ] 52 | y = [0.29R] + [0.59G] + [0.12B] 53 | 54 | Selected Approach: 3) 55 | 1) is overkill considering the result will be truncated and input is 56 | only 12-bit RGB. 57 | 2) uses divides and multiplies which are expensive in terms of 58 | dsp slices and is slow. 59 | 3) uses only shifts and adds, which is fastest and least expensive; 60 | however, this comes at cost of precision. 61 | 62 | -> use matlab to find maximum error 63 | 64 | 65 | /////////////////////////////////////////////// 66 | Intermediate Goal 1: 67 | -> Buffer camera video data in external memory 68 | -> Read video data from external memory 69 | -> Display video data via VGA 70 | 71 | 72 | 1) button debounce module 73 | - verilog testbench 74 | 75 | 2) VGA driver 76 | - formal 77 | - verilog testbench 78 | 79 | 3) independent clock FIFO 80 | - formal 81 | - systemverilog testbench 82 | 83 | 4) memory interface 84 | 85 | 5) i2c module 86 | - formal 87 | 88 | 6) system state machine 89 | - formal 90 | - systemverilog testbench 91 | 92 | /////////////////////////////////////////////// 93 | Jots: 94 | 95 | 9/19: 96 | - ps_preprocess: inspect o_valid and o_empty when i_rd is asserted and fifo is 97 | empty 98 | 99 | 9/2: 100 | - found a bug in async fifo where the wrong inequality was used for computing 101 | fill level 102 | 103 | - found a bug in async fifo where binary to graycode conversion fails for 104 | wbinnext = 0x1000. Yielding 0x1800 instead of expected 0x0800. Critical bug!! 105 | Need to find a fix still. Highest priority. 106 | -> 9/3 UPDATE: stupid typo in conversion. kinda emb 107 | 108 | - adjusted testbench to match real timings 109 | 110 | 8/31: 111 | - implemented a self-checking testbench for the capture module. 112 | 113 | - found a bug in the capture module. Incorrect default statement for the FIFO write control signal 114 | caused consecutive writes of the same data. 115 | 116 | - found a bug in the memory interface. The memory interface logic reads continuously from the camera FIFO 117 | unless the empty flag is asserted. There's a one-cycle delay on the read being deasserted, resulting in 118 | invalid data being read. 119 | -> the solution: implemented programmable almost-empty flag on the FIFO. The read-domain 120 | synchronized write pointer (double ff) is converted to binary and used to compute 121 | a fill level, which in turn is used to control the empty flag. Did the same on the 122 | write side, with a full flag. 123 | -------------------------------------------------------------------------------- /docs/sccb_notes.txt: -------------------------------------------------------------------------------- 1 | - OV7670 2 | - 2-wire SCCB 3 | - SCCB is functionally same as i2c but ack/nack bit replaced w/ don't care 4 | 5 | 6 | - SCCB 7 | -> spec: https://www.waveshare.com/w/upload/1/14/OmniVision_Technologies_Seril_Camera_Control_Bus%28SCCB%29_Specification.pdf 8 | 9 | i2c spec: https://www.nxp.com/docs/en/user-guide/UM10204.pdf 10 | -> start/stop: page 9, figure 5 11 | -> ack/nack: page 10, figure 6 12 | -> dataframe: page 15, figure 11 13 | -> timing spec: page 48 14 | 15 | - SCL 16 | - idle: logical 1 17 | 18 | - data transmission starts when SCL driven to logic 0 19 | 20 | - minimum period: t_CYC = 10us 21 | 22 | - SDA 23 | - idle: high z 24 | 25 | - can occur only when SCL is driven to logic 0 26 | 27 | - Transmission Phases 28 | 29 | +++++++++++++++ ++++++++++++++ +++++++++++++ 30 | | Phase 1 |---| Phase 2 |--| Phase 3 | 31 | Slave Address Sub-address Write Data 32 | 33 | - each phase is 9 bits 34 | - 8-bits of data, 1 ack/nack bit (don't care in SCCB) 35 | 36 | 37 | 38 | 1) START Condition: 39 | -> SDA is driven low while SCL is high 40 | __ 41 | SDA \_ 42 | ____ 43 | SCL 44 | 45 | 2) Send Bit pt1 46 | -> SCL is driven low 47 | __ 48 | SDA \___ 49 | ____ 50 | SCL \_ 51 | 52 | 3) Send Bit pt2 53 | -> When SCL is low, send bit on SDA 54 | __ _ 55 | SDA \___/_ 56 | ____ 57 | SCL \___ 58 | 59 | 4) Send Bit pt3 60 | -> Bring SCL high 61 | __ ___ 62 | SDA \___/___ 63 | ____ _ 64 | SCL \___/ 65 | 66 | 5/6) Release SDA, Check ACK 67 | -> After 8th bit of a data frame, master releases SDA, allowing slave to drive 68 | -> ACK: SDA is low on following SCL high period 69 | -> NACK: SDA is high on following SCL high period 70 | 71 | ACK: 72 | _____ 73 | SDA /__8__\_______ 74 | ___ ___ 75 | SCL __/ 8 \__/ 9 \ 76 | 77 | NACK: 78 | _____ ____ 79 | SDA /__8__\/ 80 | ___ ___ 81 | SCL __/ 8 \__/ 9 \_ 82 | 83 | - if a NACK is detected, the master can either: 84 | 1) generate a STOP condition 85 | 2) repeat a START condition to start a new transfer 86 | -> master needs to pull SCL back high 87 | 88 | */ -------------------------------------------------------------------------------- /ip/clk_wiz_0/clk_wiz_0.dcp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgeyhere/FPGA-Video-Processing/cea80bafc0d6f4e5dbbade748fdbe276a026a60c/ip/clk_wiz_0/clk_wiz_0.dcp -------------------------------------------------------------------------------- /ip/clk_wiz_0/clk_wiz_0.v: -------------------------------------------------------------------------------- 1 | 2 | // file: clk_wiz_0.v 3 | // 4 | // (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. 5 | // 6 | // This file contains confidential and proprietary information 7 | // of Xilinx, Inc. and is protected under U.S. and 8 | // international copyright and other intellectual property 9 | // laws. 10 | // 11 | // DISCLAIMER 12 | // This disclaimer is not a license and does not grant any 13 | // rights to the materials distributed herewith. Except as 14 | // otherwise provided in a valid license issued to you by 15 | // Xilinx, and to the maximum extent permitted by applicable 16 | // law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND 17 | // WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES 18 | // AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING 19 | // BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- 20 | // INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and 21 | // (2) Xilinx shall not be liable (whether in contract or tort, 22 | // including negligence, or under any other theory of 23 | // liability) for any loss or damage of any kind or nature 24 | // related to, arising under or in connection with these 25 | // materials, including for any direct, or any indirect, 26 | // special, incidental, or consequential loss or damage 27 | // (including loss of data, profits, goodwill, or any type of 28 | // loss or damage suffered as a result of any action brought 29 | // by a third party) even if such damage or loss was 30 | // reasonably foreseeable or Xilinx had been advised of the 31 | // possibility of the same. 32 | // 33 | // CRITICAL APPLICATIONS 34 | // Xilinx products are not designed or intended to be fail- 35 | // safe, or for use in any application requiring fail-safe 36 | // performance, such as life-support or safety devices or 37 | // systems, Class III medical devices, nuclear facilities, 38 | // applications related to the deployment of airbags, or any 39 | // other applications that could lead to death, personal 40 | // injury, or severe property or environmental damage 41 | // (individually and collectively, "Critical 42 | // Applications"). Customer assumes the sole risk and 43 | // liability of any use of Xilinx products in Critical 44 | // Applications, subject only to applicable laws and 45 | // regulations governing limitations on product liability. 46 | // 47 | // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS 48 | // PART OF THIS FILE AT ALL TIMES. 49 | // 50 | //---------------------------------------------------------------------------- 51 | // User entered comments 52 | //---------------------------------------------------------------------------- 53 | // None 54 | // 55 | //---------------------------------------------------------------------------- 56 | // Output Output Phase Duty Cycle Pk-to-Pk Phase 57 | // Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) 58 | //---------------------------------------------------------------------------- 59 | // clk_24MHz__24.00000______0.000______50.0______179.952____112.379 60 | // clk_25MHz__25.00000______0.000______50.0______178.503____112.379 61 | // clk_250MHz__250.00000______0.000______50.0______112.962____112.379 62 | // __clk_PS__150.00000______0.000______50.0______124.473____112.379 63 | // 64 | //---------------------------------------------------------------------------- 65 | // Input Clock Freq (MHz) Input Jitter (UI) 66 | //---------------------------------------------------------------------------- 67 | // __primary_________125.000____________0.010 68 | 69 | `timescale 1ps/1ps 70 | 71 | (* CORE_GENERATION_INFO = "clk_wiz_0,clk_wiz_v6_0_6_0_0,{component_name=clk_wiz_0,use_phase_alignment=true,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,enable_axi=0,feedback_source=FDBK_AUTO,PRIMITIVE=MMCM,num_out_clk=4,clkin1_period=8.000,clkin2_period=10.0,use_power_down=false,use_reset=true,use_locked=false,use_inclk_stopped=false,feedback_type=SINGLE,CLOCK_MGR_TYPE=NA,manual_override=false}" *) 72 | 73 | module clk_wiz_0 74 | ( 75 | // Clock out ports 76 | output clk_24MHz, 77 | output clk_25MHz, 78 | output clk_250MHz, 79 | output clk_PS, 80 | // Status and control signals 81 | input reset, 82 | // Clock in ports 83 | input clk_in1 84 | ); 85 | 86 | clk_wiz_0_clk_wiz inst 87 | ( 88 | // Clock out ports 89 | .clk_24MHz(clk_24MHz), 90 | .clk_25MHz(clk_25MHz), 91 | .clk_250MHz(clk_250MHz), 92 | .clk_PS(clk_PS), 93 | // Status and control signals 94 | .reset(reset), 95 | // Clock in ports 96 | .clk_in1(clk_in1) 97 | ); 98 | 99 | endmodule 100 | -------------------------------------------------------------------------------- /ip/clk_wiz_0/clk_wiz_0.veo: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. 4 | // 5 | // This file contains confidential and proprietary information 6 | // of Xilinx, Inc. and is protected under U.S. and 7 | // international copyright and other intellectual property 8 | // laws. 9 | // 10 | // DISCLAIMER 11 | // This disclaimer is not a license and does not grant any 12 | // rights to the materials distributed herewith. Except as 13 | // otherwise provided in a valid license issued to you by 14 | // Xilinx, and to the maximum extent permitted by applicable 15 | // law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND 16 | // WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES 17 | // AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING 18 | // BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- 19 | // INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and 20 | // (2) Xilinx shall not be liable (whether in contract or tort, 21 | // including negligence, or under any other theory of 22 | // liability) for any loss or damage of any kind or nature 23 | // related to, arising under or in connection with these 24 | // materials, including for any direct, or any indirect, 25 | // special, incidental, or consequential loss or damage 26 | // (including loss of data, profits, goodwill, or any type of 27 | // loss or damage suffered as a result of any action brought 28 | // by a third party) even if such damage or loss was 29 | // reasonably foreseeable or Xilinx had been advised of the 30 | // possibility of the same. 31 | // 32 | // CRITICAL APPLICATIONS 33 | // Xilinx products are not designed or intended to be fail- 34 | // safe, or for use in any application requiring fail-safe 35 | // performance, such as life-support or safety devices or 36 | // systems, Class III medical devices, nuclear facilities, 37 | // applications related to the deployment of airbags, or any 38 | // other applications that could lead to death, personal 39 | // injury, or severe property or environmental damage 40 | // (individually and collectively, "Critical 41 | // Applications"). Customer assumes the sole risk and 42 | // liability of any use of Xilinx products in Critical 43 | // Applications, subject only to applicable laws and 44 | // regulations governing limitations on product liability. 45 | // 46 | // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS 47 | // PART OF THIS FILE AT ALL TIMES. 48 | // 49 | //---------------------------------------------------------------------------- 50 | // User entered comments 51 | //---------------------------------------------------------------------------- 52 | // None 53 | // 54 | //---------------------------------------------------------------------------- 55 | // Output Output Phase Duty Cycle Pk-to-Pk Phase 56 | // Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) 57 | //---------------------------------------------------------------------------- 58 | // clk_24MHz__24.00000______0.000______50.0______179.952____112.379 59 | // clk_25MHz__25.00000______0.000______50.0______178.503____112.379 60 | // clk_250MHz__250.00000______0.000______50.0______112.962____112.379 61 | // __clk_PS__150.00000______0.000______50.0______124.473____112.379 62 | // 63 | //---------------------------------------------------------------------------- 64 | // Input Clock Freq (MHz) Input Jitter (UI) 65 | //---------------------------------------------------------------------------- 66 | // __primary_________125.000____________0.010 67 | 68 | // The following must be inserted into your Verilog file for this 69 | // core to be instantiated. Change the instance name and port connections 70 | // (in parentheses) to your own signal names. 71 | 72 | //----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG 73 | 74 | clk_wiz_0 instance_name 75 | ( 76 | // Clock out ports 77 | .clk_24MHz(clk_24MHz), // output clk_24MHz 78 | .clk_25MHz(clk_25MHz), // output clk_25MHz 79 | .clk_250MHz(clk_250MHz), // output clk_250MHz 80 | .clk_PS(clk_PS), // output clk_PS 81 | // Status and control signals 82 | .reset(reset), // input reset 83 | // Clock in ports 84 | .clk_in1(clk_in1)); // input clk_in1 85 | 86 | // INST_TAG_END ------ End INSTANTIATION Template --------- 87 | -------------------------------------------------------------------------------- /ip/clk_wiz_0/clk_wiz_0.xdc: -------------------------------------------------------------------------------- 1 | 2 | # file: clk_wiz_0.xdc 3 | # 4 | # (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. 5 | # 6 | # This file contains confidential and proprietary information 7 | # of Xilinx, Inc. and is protected under U.S. and 8 | # international copyright and other intellectual property 9 | # laws. 10 | # 11 | # DISCLAIMER 12 | # This disclaimer is not a license and does not grant any 13 | # rights to the materials distributed herewith. Except as 14 | # otherwise provided in a valid license issued to you by 15 | # Xilinx, and to the maximum extent permitted by applicable 16 | # law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND 17 | # WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES 18 | # AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING 19 | # BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- 20 | # INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and 21 | # (2) Xilinx shall not be liable (whether in contract or tort, 22 | # including negligence, or under any other theory of 23 | # liability) for any loss or damage of any kind or nature 24 | # related to, arising under or in connection with these 25 | # materials, including for any direct, or any indirect, 26 | # special, incidental, or consequential loss or damage 27 | # (including loss of data, profits, goodwill, or any type of 28 | # loss or damage suffered as a result of any action brought 29 | # by a third party) even if such damage or loss was 30 | # reasonably foreseeable or Xilinx had been advised of the 31 | # possibility of the same. 32 | # 33 | # CRITICAL APPLICATIONS 34 | # Xilinx products are not designed or intended to be fail- 35 | # safe, or for use in any application requiring fail-safe 36 | # performance, such as life-support or safety devices or 37 | # systems, Class III medical devices, nuclear facilities, 38 | # applications related to the deployment of airbags, or any 39 | # other applications that could lead to death, personal 40 | # injury, or severe property or environmental damage 41 | # (individually and collectively, "Critical 42 | # Applications"). Customer assumes the sole risk and 43 | # liability of any use of Xilinx products in Critical 44 | # Applications, subject only to applicable laws and 45 | # regulations governing limitations on product liability. 46 | # 47 | # THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS 48 | # PART OF THIS FILE AT ALL TIMES. 49 | # 50 | 51 | # Input clock periods. These duplicate the values entered for the 52 | # input clocks. You can use these to time your system. If required 53 | # commented constraints can be used in the top level xdc 54 | #---------------------------------------------------------------- 55 | # Connect to input port when clock capable pin is selected for input 56 | create_clock -period 8.000 [get_ports clk_in1] 57 | set_input_jitter [get_clocks -of_objects [get_ports clk_in1]] 0.08 58 | 59 | 60 | set_property PHASESHIFT_MODE WAVEFORM [get_cells -hierarchical *adv*] 61 | -------------------------------------------------------------------------------- /ip/clk_wiz_0/clk_wiz_0_board.xdc: -------------------------------------------------------------------------------- 1 | #--------------------Physical Constraints----------------- 2 | 3 | set_property BOARD_PIN {sys_clk} [get_ports clk_in1] 4 | -------------------------------------------------------------------------------- /ip/clk_wiz_0/clk_wiz_0_clk_wiz.v: -------------------------------------------------------------------------------- 1 | 2 | // file: clk_wiz_0.v 3 | // 4 | // (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. 5 | // 6 | // This file contains confidential and proprietary information 7 | // of Xilinx, Inc. and is protected under U.S. and 8 | // international copyright and other intellectual property 9 | // laws. 10 | // 11 | // DISCLAIMER 12 | // This disclaimer is not a license and does not grant any 13 | // rights to the materials distributed herewith. Except as 14 | // otherwise provided in a valid license issued to you by 15 | // Xilinx, and to the maximum extent permitted by applicable 16 | // law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND 17 | // WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES 18 | // AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING 19 | // BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- 20 | // INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and 21 | // (2) Xilinx shall not be liable (whether in contract or tort, 22 | // including negligence, or under any other theory of 23 | // liability) for any loss or damage of any kind or nature 24 | // related to, arising under or in connection with these 25 | // materials, including for any direct, or any indirect, 26 | // special, incidental, or consequential loss or damage 27 | // (including loss of data, profits, goodwill, or any type of 28 | // loss or damage suffered as a result of any action brought 29 | // by a third party) even if such damage or loss was 30 | // reasonably foreseeable or Xilinx had been advised of the 31 | // possibility of the same. 32 | // 33 | // CRITICAL APPLICATIONS 34 | // Xilinx products are not designed or intended to be fail- 35 | // safe, or for use in any application requiring fail-safe 36 | // performance, such as life-support or safety devices or 37 | // systems, Class III medical devices, nuclear facilities, 38 | // applications related to the deployment of airbags, or any 39 | // other applications that could lead to death, personal 40 | // injury, or severe property or environmental damage 41 | // (individually and collectively, "Critical 42 | // Applications"). Customer assumes the sole risk and 43 | // liability of any use of Xilinx products in Critical 44 | // Applications, subject only to applicable laws and 45 | // regulations governing limitations on product liability. 46 | // 47 | // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS 48 | // PART OF THIS FILE AT ALL TIMES. 49 | // 50 | //---------------------------------------------------------------------------- 51 | // User entered comments 52 | //---------------------------------------------------------------------------- 53 | // None 54 | // 55 | //---------------------------------------------------------------------------- 56 | // Output Output Phase Duty Cycle Pk-to-Pk Phase 57 | // Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) 58 | //---------------------------------------------------------------------------- 59 | // clk_24MHz__24.00000______0.000______50.0______179.952____112.379 60 | // clk_25MHz__25.00000______0.000______50.0______178.503____112.379 61 | // clk_250MHz__250.00000______0.000______50.0______112.962____112.379 62 | // __clk_PS__150.00000______0.000______50.0______124.473____112.379 63 | // 64 | //---------------------------------------------------------------------------- 65 | // Input Clock Freq (MHz) Input Jitter (UI) 66 | //---------------------------------------------------------------------------- 67 | // __primary_________125.000____________0.010 68 | 69 | `timescale 1ps/1ps 70 | 71 | module clk_wiz_0_clk_wiz 72 | 73 | (// Clock in ports 74 | // Clock out ports 75 | output clk_24MHz, 76 | output clk_25MHz, 77 | output clk_250MHz, 78 | output clk_PS, 79 | // Status and control signals 80 | input reset, 81 | input clk_in1 82 | ); 83 | // Input buffering 84 | //------------------------------------ 85 | wire clk_in1_clk_wiz_0; 86 | wire clk_in2_clk_wiz_0; 87 | IBUF clkin1_ibufg 88 | (.O (clk_in1_clk_wiz_0), 89 | .I (clk_in1)); 90 | 91 | 92 | 93 | 94 | // Clocking PRIMITIVE 95 | //------------------------------------ 96 | 97 | // Instantiation of the MMCM PRIMITIVE 98 | // * Unused inputs are tied off 99 | // * Unused outputs are labeled unused 100 | 101 | wire clk_24MHz_clk_wiz_0; 102 | wire clk_25MHz_clk_wiz_0; 103 | wire clk_250MHz_clk_wiz_0; 104 | wire clk_PS_clk_wiz_0; 105 | wire clk_out5_clk_wiz_0; 106 | wire clk_out6_clk_wiz_0; 107 | wire clk_out7_clk_wiz_0; 108 | 109 | wire [15:0] do_unused; 110 | wire drdy_unused; 111 | wire psdone_unused; 112 | wire locked_int; 113 | wire clkfbout_clk_wiz_0; 114 | wire clkfbout_buf_clk_wiz_0; 115 | wire clkfboutb_unused; 116 | wire clkout0b_unused; 117 | wire clkout1b_unused; 118 | wire clkout2b_unused; 119 | wire clkout3b_unused; 120 | wire clkout4_unused; 121 | wire clkout5_unused; 122 | wire clkout6_unused; 123 | wire clkfbstopped_unused; 124 | wire clkinstopped_unused; 125 | wire reset_high; 126 | 127 | MMCME2_ADV 128 | #(.BANDWIDTH ("OPTIMIZED"), 129 | .CLKOUT4_CASCADE ("FALSE"), 130 | .COMPENSATION ("ZHOLD"), 131 | .STARTUP_WAIT ("FALSE"), 132 | .DIVCLK_DIVIDE (1), 133 | .CLKFBOUT_MULT_F (6.000), 134 | .CLKFBOUT_PHASE (0.000), 135 | .CLKFBOUT_USE_FINE_PS ("FALSE"), 136 | .CLKOUT0_DIVIDE_F (31.250), 137 | .CLKOUT0_PHASE (0.000), 138 | .CLKOUT0_DUTY_CYCLE (0.500), 139 | .CLKOUT0_USE_FINE_PS ("FALSE"), 140 | .CLKOUT1_DIVIDE (30), 141 | .CLKOUT1_PHASE (0.000), 142 | .CLKOUT1_DUTY_CYCLE (0.500), 143 | .CLKOUT1_USE_FINE_PS ("FALSE"), 144 | .CLKOUT2_DIVIDE (3), 145 | .CLKOUT2_PHASE (0.000), 146 | .CLKOUT2_DUTY_CYCLE (0.500), 147 | .CLKOUT2_USE_FINE_PS ("FALSE"), 148 | .CLKOUT3_DIVIDE (5), 149 | .CLKOUT3_PHASE (0.000), 150 | .CLKOUT3_DUTY_CYCLE (0.500), 151 | .CLKOUT3_USE_FINE_PS ("FALSE"), 152 | .CLKIN1_PERIOD (8.000)) 153 | mmcm_adv_inst 154 | // Output clocks 155 | ( 156 | .CLKFBOUT (clkfbout_clk_wiz_0), 157 | .CLKFBOUTB (clkfboutb_unused), 158 | .CLKOUT0 (clk_24MHz_clk_wiz_0), 159 | .CLKOUT0B (clkout0b_unused), 160 | .CLKOUT1 (clk_25MHz_clk_wiz_0), 161 | .CLKOUT1B (clkout1b_unused), 162 | .CLKOUT2 (clk_250MHz_clk_wiz_0), 163 | .CLKOUT2B (clkout2b_unused), 164 | .CLKOUT3 (clk_PS_clk_wiz_0), 165 | .CLKOUT3B (clkout3b_unused), 166 | .CLKOUT4 (clkout4_unused), 167 | .CLKOUT5 (clkout5_unused), 168 | .CLKOUT6 (clkout6_unused), 169 | // Input clock control 170 | .CLKFBIN (clkfbout_buf_clk_wiz_0), 171 | .CLKIN1 (clk_in1_clk_wiz_0), 172 | .CLKIN2 (1'b0), 173 | // Tied to always select the primary input clock 174 | .CLKINSEL (1'b1), 175 | // Ports for dynamic reconfiguration 176 | .DADDR (7'h0), 177 | .DCLK (1'b0), 178 | .DEN (1'b0), 179 | .DI (16'h0), 180 | .DO (do_unused), 181 | .DRDY (drdy_unused), 182 | .DWE (1'b0), 183 | // Ports for dynamic phase shift 184 | .PSCLK (1'b0), 185 | .PSEN (1'b0), 186 | .PSINCDEC (1'b0), 187 | .PSDONE (psdone_unused), 188 | // Other control and status signals 189 | .LOCKED (locked_int), 190 | .CLKINSTOPPED (clkinstopped_unused), 191 | .CLKFBSTOPPED (clkfbstopped_unused), 192 | .PWRDWN (1'b0), 193 | .RST (reset_high)); 194 | assign reset_high = reset; 195 | 196 | // Clock Monitor clock assigning 197 | //-------------------------------------- 198 | // Output buffering 199 | //----------------------------------- 200 | 201 | BUFG clkf_buf 202 | (.O (clkfbout_buf_clk_wiz_0), 203 | .I (clkfbout_clk_wiz_0)); 204 | 205 | 206 | 207 | 208 | 209 | 210 | BUFG clkout1_buf 211 | (.O (clk_24MHz), 212 | .I (clk_24MHz_clk_wiz_0)); 213 | 214 | 215 | BUFG clkout2_buf 216 | (.O (clk_25MHz), 217 | .I (clk_25MHz_clk_wiz_0)); 218 | 219 | BUFG clkout3_buf 220 | (.O (clk_250MHz), 221 | .I (clk_250MHz_clk_wiz_0)); 222 | 223 | BUFG clkout4_buf 224 | (.O (clk_PS), 225 | .I (clk_PS_clk_wiz_0)); 226 | 227 | 228 | 229 | endmodule 230 | -------------------------------------------------------------------------------- /ip/clk_wiz_0/clk_wiz_0_ooc.xdc: -------------------------------------------------------------------------------- 1 | 2 | # file: clk_wiz_0_ooc.xdc 3 | # 4 | # (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. 5 | # 6 | # This file contains confidential and proprietary information 7 | # of Xilinx, Inc. and is protected under U.S. and 8 | # international copyright and other intellectual property 9 | # laws. 10 | # 11 | # DISCLAIMER 12 | # This disclaimer is not a license and does not grant any 13 | # rights to the materials distributed herewith. Except as 14 | # otherwise provided in a valid license issued to you by 15 | # Xilinx, and to the maximum extent permitted by applicable 16 | # law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND 17 | # WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES 18 | # AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING 19 | # BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- 20 | # INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and 21 | # (2) Xilinx shall not be liable (whether in contract or tort, 22 | # including negligence, or under any other theory of 23 | # liability) for any loss or damage of any kind or nature 24 | # related to, arising under or in connection with these 25 | # materials, including for any direct, or any indirect, 26 | # special, incidental, or consequential loss or damage 27 | # (including loss of data, profits, goodwill, or any type of 28 | # loss or damage suffered as a result of any action brought 29 | # by a third party) even if such damage or loss was 30 | # reasonably foreseeable or Xilinx had been advised of the 31 | # possibility of the same. 32 | # 33 | # CRITICAL APPLICATIONS 34 | # Xilinx products are not designed or intended to be fail- 35 | # safe, or for use in any application requiring fail-safe 36 | # performance, such as life-support or safety devices or 37 | # systems, Class III medical devices, nuclear facilities, 38 | # applications related to the deployment of airbags, or any 39 | # other applications that could lead to death, personal 40 | # injury, or severe property or environmental damage 41 | # (individually and collectively, "Critical 42 | # Applications"). Customer assumes the sole risk and 43 | # liability of any use of Xilinx products in Critical 44 | # Applications, subject only to applicable laws and 45 | # regulations governing limitations on product liability. 46 | # 47 | # THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS 48 | # PART OF THIS FILE AT ALL TIMES. 49 | # 50 | 51 | ################# 52 | #DEFAULT CLOCK CONSTRAINTS 53 | 54 | ############################################################ 55 | # Clock Period Constraints # 56 | ############################################################ 57 | #create_clock -period 8.000 [get_ports clk_in1] 58 | 59 | -------------------------------------------------------------------------------- /ip/clk_wiz_0/clk_wiz_0_sim_netlist.v: -------------------------------------------------------------------------------- 1 | // Copyright 1986-2020 Xilinx, Inc. All Rights Reserved. 2 | // -------------------------------------------------------------------------------- 3 | // Tool Version: Vivado v.2020.2 (win64) Build 3064766 Wed Nov 18 09:12:45 MST 2020 4 | // Date : Sun Sep 19 19:53:33 2021 5 | // Host : DESKTOP-MB5IJCE running 64-bit major release (build 9200) 6 | // Command : write_verilog -force -mode funcsim 7 | // c:/Users/work/Documents/repos/Edge-Detection/ip/clk_wiz_0/clk_wiz_0_sim_netlist.v 8 | // Design : clk_wiz_0 9 | // Purpose : This verilog netlist is a functional simulation representation of the design and should not be modified 10 | // or synthesized. This netlist cannot be used for SDF annotated simulation. 11 | // Device : xc7z020clg400-1 12 | // -------------------------------------------------------------------------------- 13 | `timescale 1 ps / 1 ps 14 | 15 | (* NotValidForBitStream *) 16 | module clk_wiz_0 17 | (clk_24MHz, 18 | clk_25MHz, 19 | clk_250MHz, 20 | clk_PS, 21 | reset, 22 | clk_in1); 23 | output clk_24MHz; 24 | output clk_25MHz; 25 | output clk_250MHz; 26 | output clk_PS; 27 | input reset; 28 | input clk_in1; 29 | 30 | wire clk_24MHz; 31 | wire clk_250MHz; 32 | wire clk_25MHz; 33 | wire clk_PS; 34 | (* IBUF_LOW_PWR *) (* RTL_KEEP = "yes" *) wire clk_in1; 35 | wire reset; 36 | 37 | clk_wiz_0_clk_wiz_0_clk_wiz inst 38 | (.clk_24MHz(clk_24MHz), 39 | .clk_250MHz(clk_250MHz), 40 | .clk_25MHz(clk_25MHz), 41 | .clk_PS(clk_PS), 42 | .clk_in1(clk_in1), 43 | .reset(reset)); 44 | endmodule 45 | 46 | (* ORIG_REF_NAME = "clk_wiz_0_clk_wiz" *) 47 | module clk_wiz_0_clk_wiz_0_clk_wiz 48 | (clk_24MHz, 49 | clk_25MHz, 50 | clk_250MHz, 51 | clk_PS, 52 | reset, 53 | clk_in1); 54 | output clk_24MHz; 55 | output clk_25MHz; 56 | output clk_250MHz; 57 | output clk_PS; 58 | input reset; 59 | input clk_in1; 60 | 61 | wire clk_24MHz; 62 | wire clk_24MHz_clk_wiz_0; 63 | wire clk_250MHz; 64 | wire clk_250MHz_clk_wiz_0; 65 | wire clk_25MHz; 66 | wire clk_25MHz_clk_wiz_0; 67 | wire clk_PS; 68 | wire clk_PS_clk_wiz_0; 69 | wire clk_in1; 70 | wire clk_in1_clk_wiz_0; 71 | wire clkfbout_buf_clk_wiz_0; 72 | wire clkfbout_clk_wiz_0; 73 | wire reset; 74 | wire NLW_mmcm_adv_inst_CLKFBOUTB_UNCONNECTED; 75 | wire NLW_mmcm_adv_inst_CLKFBSTOPPED_UNCONNECTED; 76 | wire NLW_mmcm_adv_inst_CLKINSTOPPED_UNCONNECTED; 77 | wire NLW_mmcm_adv_inst_CLKOUT0B_UNCONNECTED; 78 | wire NLW_mmcm_adv_inst_CLKOUT1B_UNCONNECTED; 79 | wire NLW_mmcm_adv_inst_CLKOUT2B_UNCONNECTED; 80 | wire NLW_mmcm_adv_inst_CLKOUT3B_UNCONNECTED; 81 | wire NLW_mmcm_adv_inst_CLKOUT4_UNCONNECTED; 82 | wire NLW_mmcm_adv_inst_CLKOUT5_UNCONNECTED; 83 | wire NLW_mmcm_adv_inst_CLKOUT6_UNCONNECTED; 84 | wire NLW_mmcm_adv_inst_DRDY_UNCONNECTED; 85 | wire NLW_mmcm_adv_inst_LOCKED_UNCONNECTED; 86 | wire NLW_mmcm_adv_inst_PSDONE_UNCONNECTED; 87 | wire [15:0]NLW_mmcm_adv_inst_DO_UNCONNECTED; 88 | 89 | (* BOX_TYPE = "PRIMITIVE" *) 90 | BUFG clkf_buf 91 | (.I(clkfbout_clk_wiz_0), 92 | .O(clkfbout_buf_clk_wiz_0)); 93 | (* BOX_TYPE = "PRIMITIVE" *) 94 | (* CAPACITANCE = "DONT_CARE" *) 95 | (* IBUF_DELAY_VALUE = "0" *) 96 | (* IFD_DELAY_VALUE = "AUTO" *) 97 | IBUF #( 98 | .IOSTANDARD("DEFAULT")) 99 | clkin1_ibufg 100 | (.I(clk_in1), 101 | .O(clk_in1_clk_wiz_0)); 102 | (* BOX_TYPE = "PRIMITIVE" *) 103 | BUFG clkout1_buf 104 | (.I(clk_24MHz_clk_wiz_0), 105 | .O(clk_24MHz)); 106 | (* BOX_TYPE = "PRIMITIVE" *) 107 | BUFG clkout2_buf 108 | (.I(clk_25MHz_clk_wiz_0), 109 | .O(clk_25MHz)); 110 | (* BOX_TYPE = "PRIMITIVE" *) 111 | BUFG clkout3_buf 112 | (.I(clk_250MHz_clk_wiz_0), 113 | .O(clk_250MHz)); 114 | (* BOX_TYPE = "PRIMITIVE" *) 115 | BUFG clkout4_buf 116 | (.I(clk_PS_clk_wiz_0), 117 | .O(clk_PS)); 118 | (* BOX_TYPE = "PRIMITIVE" *) 119 | MMCME2_ADV #( 120 | .BANDWIDTH("OPTIMIZED"), 121 | .CLKFBOUT_MULT_F(6.000000), 122 | .CLKFBOUT_PHASE(0.000000), 123 | .CLKFBOUT_USE_FINE_PS("FALSE"), 124 | .CLKIN1_PERIOD(8.000000), 125 | .CLKIN2_PERIOD(0.000000), 126 | .CLKOUT0_DIVIDE_F(31.250000), 127 | .CLKOUT0_DUTY_CYCLE(0.500000), 128 | .CLKOUT0_PHASE(0.000000), 129 | .CLKOUT0_USE_FINE_PS("FALSE"), 130 | .CLKOUT1_DIVIDE(30), 131 | .CLKOUT1_DUTY_CYCLE(0.500000), 132 | .CLKOUT1_PHASE(0.000000), 133 | .CLKOUT1_USE_FINE_PS("FALSE"), 134 | .CLKOUT2_DIVIDE(3), 135 | .CLKOUT2_DUTY_CYCLE(0.500000), 136 | .CLKOUT2_PHASE(0.000000), 137 | .CLKOUT2_USE_FINE_PS("FALSE"), 138 | .CLKOUT3_DIVIDE(5), 139 | .CLKOUT3_DUTY_CYCLE(0.500000), 140 | .CLKOUT3_PHASE(0.000000), 141 | .CLKOUT3_USE_FINE_PS("FALSE"), 142 | .CLKOUT4_CASCADE("FALSE"), 143 | .CLKOUT4_DIVIDE(1), 144 | .CLKOUT4_DUTY_CYCLE(0.500000), 145 | .CLKOUT4_PHASE(0.000000), 146 | .CLKOUT4_USE_FINE_PS("FALSE"), 147 | .CLKOUT5_DIVIDE(1), 148 | .CLKOUT5_DUTY_CYCLE(0.500000), 149 | .CLKOUT5_PHASE(0.000000), 150 | .CLKOUT5_USE_FINE_PS("FALSE"), 151 | .CLKOUT6_DIVIDE(1), 152 | .CLKOUT6_DUTY_CYCLE(0.500000), 153 | .CLKOUT6_PHASE(0.000000), 154 | .CLKOUT6_USE_FINE_PS("FALSE"), 155 | .COMPENSATION("ZHOLD"), 156 | .DIVCLK_DIVIDE(1), 157 | .IS_CLKINSEL_INVERTED(1'b0), 158 | .IS_PSEN_INVERTED(1'b0), 159 | .IS_PSINCDEC_INVERTED(1'b0), 160 | .IS_PWRDWN_INVERTED(1'b0), 161 | .IS_RST_INVERTED(1'b0), 162 | .REF_JITTER1(0.010000), 163 | .REF_JITTER2(0.010000), 164 | .SS_EN("FALSE"), 165 | .SS_MODE("CENTER_HIGH"), 166 | .SS_MOD_PERIOD(10000), 167 | .STARTUP_WAIT("FALSE")) 168 | mmcm_adv_inst 169 | (.CLKFBIN(clkfbout_buf_clk_wiz_0), 170 | .CLKFBOUT(clkfbout_clk_wiz_0), 171 | .CLKFBOUTB(NLW_mmcm_adv_inst_CLKFBOUTB_UNCONNECTED), 172 | .CLKFBSTOPPED(NLW_mmcm_adv_inst_CLKFBSTOPPED_UNCONNECTED), 173 | .CLKIN1(clk_in1_clk_wiz_0), 174 | .CLKIN2(1'b0), 175 | .CLKINSEL(1'b1), 176 | .CLKINSTOPPED(NLW_mmcm_adv_inst_CLKINSTOPPED_UNCONNECTED), 177 | .CLKOUT0(clk_24MHz_clk_wiz_0), 178 | .CLKOUT0B(NLW_mmcm_adv_inst_CLKOUT0B_UNCONNECTED), 179 | .CLKOUT1(clk_25MHz_clk_wiz_0), 180 | .CLKOUT1B(NLW_mmcm_adv_inst_CLKOUT1B_UNCONNECTED), 181 | .CLKOUT2(clk_250MHz_clk_wiz_0), 182 | .CLKOUT2B(NLW_mmcm_adv_inst_CLKOUT2B_UNCONNECTED), 183 | .CLKOUT3(clk_PS_clk_wiz_0), 184 | .CLKOUT3B(NLW_mmcm_adv_inst_CLKOUT3B_UNCONNECTED), 185 | .CLKOUT4(NLW_mmcm_adv_inst_CLKOUT4_UNCONNECTED), 186 | .CLKOUT5(NLW_mmcm_adv_inst_CLKOUT5_UNCONNECTED), 187 | .CLKOUT6(NLW_mmcm_adv_inst_CLKOUT6_UNCONNECTED), 188 | .DADDR({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}), 189 | .DCLK(1'b0), 190 | .DEN(1'b0), 191 | .DI({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}), 192 | .DO(NLW_mmcm_adv_inst_DO_UNCONNECTED[15:0]), 193 | .DRDY(NLW_mmcm_adv_inst_DRDY_UNCONNECTED), 194 | .DWE(1'b0), 195 | .LOCKED(NLW_mmcm_adv_inst_LOCKED_UNCONNECTED), 196 | .PSCLK(1'b0), 197 | .PSDONE(NLW_mmcm_adv_inst_PSDONE_UNCONNECTED), 198 | .PSEN(1'b0), 199 | .PSINCDEC(1'b0), 200 | .PWRDWN(1'b0), 201 | .RST(reset)); 202 | endmodule 203 | `ifndef GLBL 204 | `define GLBL 205 | `timescale 1 ps / 1 ps 206 | 207 | module glbl (); 208 | 209 | parameter ROC_WIDTH = 100000; 210 | parameter TOC_WIDTH = 0; 211 | parameter GRES_WIDTH = 10000; 212 | parameter GRES_START = 10000; 213 | 214 | //-------- STARTUP Globals -------------- 215 | wire GSR; 216 | wire GTS; 217 | wire GWE; 218 | wire PRLD; 219 | wire GRESTORE; 220 | tri1 p_up_tmp; 221 | tri (weak1, strong0) PLL_LOCKG = p_up_tmp; 222 | 223 | wire PROGB_GLBL; 224 | wire CCLKO_GLBL; 225 | wire FCSBO_GLBL; 226 | wire [3:0] DO_GLBL; 227 | wire [3:0] DI_GLBL; 228 | 229 | reg GSR_int; 230 | reg GTS_int; 231 | reg PRLD_int; 232 | reg GRESTORE_int; 233 | 234 | //-------- JTAG Globals -------------- 235 | wire JTAG_TDO_GLBL; 236 | wire JTAG_TCK_GLBL; 237 | wire JTAG_TDI_GLBL; 238 | wire JTAG_TMS_GLBL; 239 | wire JTAG_TRST_GLBL; 240 | 241 | reg JTAG_CAPTURE_GLBL; 242 | reg JTAG_RESET_GLBL; 243 | reg JTAG_SHIFT_GLBL; 244 | reg JTAG_UPDATE_GLBL; 245 | reg JTAG_RUNTEST_GLBL; 246 | 247 | reg JTAG_SEL1_GLBL = 0; 248 | reg JTAG_SEL2_GLBL = 0 ; 249 | reg JTAG_SEL3_GLBL = 0; 250 | reg JTAG_SEL4_GLBL = 0; 251 | 252 | reg JTAG_USER_TDO1_GLBL = 1'bz; 253 | reg JTAG_USER_TDO2_GLBL = 1'bz; 254 | reg JTAG_USER_TDO3_GLBL = 1'bz; 255 | reg JTAG_USER_TDO4_GLBL = 1'bz; 256 | 257 | assign (strong1, weak0) GSR = GSR_int; 258 | assign (strong1, weak0) GTS = GTS_int; 259 | assign (weak1, weak0) PRLD = PRLD_int; 260 | assign (strong1, weak0) GRESTORE = GRESTORE_int; 261 | 262 | initial begin 263 | GSR_int = 1'b1; 264 | PRLD_int = 1'b1; 265 | #(ROC_WIDTH) 266 | GSR_int = 1'b0; 267 | PRLD_int = 1'b0; 268 | end 269 | 270 | initial begin 271 | GTS_int = 1'b1; 272 | #(TOC_WIDTH) 273 | GTS_int = 1'b0; 274 | end 275 | 276 | initial begin 277 | GRESTORE_int = 1'b0; 278 | #(GRES_START); 279 | GRESTORE_int = 1'b1; 280 | #(GRES_WIDTH); 281 | GRESTORE_int = 1'b0; 282 | end 283 | 284 | endmodule 285 | `endif 286 | -------------------------------------------------------------------------------- /ip/clk_wiz_0/clk_wiz_0_sim_netlist.vhdl: -------------------------------------------------------------------------------- 1 | -- Copyright 1986-2020 Xilinx, Inc. All Rights Reserved. 2 | -- -------------------------------------------------------------------------------- 3 | -- Tool Version: Vivado v.2020.2 (win64) Build 3064766 Wed Nov 18 09:12:45 MST 2020 4 | -- Date : Sun Sep 19 19:53:33 2021 5 | -- Host : DESKTOP-MB5IJCE running 64-bit major release (build 9200) 6 | -- Command : write_vhdl -force -mode funcsim 7 | -- c:/Users/work/Documents/repos/Edge-Detection/ip/clk_wiz_0/clk_wiz_0_sim_netlist.vhdl 8 | -- Design : clk_wiz_0 9 | -- Purpose : This VHDL netlist is a functional simulation representation of the design and should not be modified or 10 | -- synthesized. This netlist cannot be used for SDF annotated simulation. 11 | -- Device : xc7z020clg400-1 12 | -- -------------------------------------------------------------------------------- 13 | library IEEE; 14 | use IEEE.STD_LOGIC_1164.ALL; 15 | library UNISIM; 16 | use UNISIM.VCOMPONENTS.ALL; 17 | entity clk_wiz_0_clk_wiz_0_clk_wiz is 18 | port ( 19 | clk_24MHz : out STD_LOGIC; 20 | clk_25MHz : out STD_LOGIC; 21 | clk_250MHz : out STD_LOGIC; 22 | clk_PS : out STD_LOGIC; 23 | reset : in STD_LOGIC; 24 | clk_in1 : in STD_LOGIC 25 | ); 26 | attribute ORIG_REF_NAME : string; 27 | attribute ORIG_REF_NAME of clk_wiz_0_clk_wiz_0_clk_wiz : entity is "clk_wiz_0_clk_wiz"; 28 | end clk_wiz_0_clk_wiz_0_clk_wiz; 29 | 30 | architecture STRUCTURE of clk_wiz_0_clk_wiz_0_clk_wiz is 31 | signal clk_24MHz_clk_wiz_0 : STD_LOGIC; 32 | signal clk_250MHz_clk_wiz_0 : STD_LOGIC; 33 | signal clk_25MHz_clk_wiz_0 : STD_LOGIC; 34 | signal clk_PS_clk_wiz_0 : STD_LOGIC; 35 | signal clk_in1_clk_wiz_0 : STD_LOGIC; 36 | signal clkfbout_buf_clk_wiz_0 : STD_LOGIC; 37 | signal clkfbout_clk_wiz_0 : STD_LOGIC; 38 | signal NLW_mmcm_adv_inst_CLKFBOUTB_UNCONNECTED : STD_LOGIC; 39 | signal NLW_mmcm_adv_inst_CLKFBSTOPPED_UNCONNECTED : STD_LOGIC; 40 | signal NLW_mmcm_adv_inst_CLKINSTOPPED_UNCONNECTED : STD_LOGIC; 41 | signal NLW_mmcm_adv_inst_CLKOUT0B_UNCONNECTED : STD_LOGIC; 42 | signal NLW_mmcm_adv_inst_CLKOUT1B_UNCONNECTED : STD_LOGIC; 43 | signal NLW_mmcm_adv_inst_CLKOUT2B_UNCONNECTED : STD_LOGIC; 44 | signal NLW_mmcm_adv_inst_CLKOUT3B_UNCONNECTED : STD_LOGIC; 45 | signal NLW_mmcm_adv_inst_CLKOUT4_UNCONNECTED : STD_LOGIC; 46 | signal NLW_mmcm_adv_inst_CLKOUT5_UNCONNECTED : STD_LOGIC; 47 | signal NLW_mmcm_adv_inst_CLKOUT6_UNCONNECTED : STD_LOGIC; 48 | signal NLW_mmcm_adv_inst_DRDY_UNCONNECTED : STD_LOGIC; 49 | signal NLW_mmcm_adv_inst_LOCKED_UNCONNECTED : STD_LOGIC; 50 | signal NLW_mmcm_adv_inst_PSDONE_UNCONNECTED : STD_LOGIC; 51 | signal NLW_mmcm_adv_inst_DO_UNCONNECTED : STD_LOGIC_VECTOR ( 15 downto 0 ); 52 | attribute BOX_TYPE : string; 53 | attribute BOX_TYPE of clkf_buf : label is "PRIMITIVE"; 54 | attribute BOX_TYPE of clkin1_ibufg : label is "PRIMITIVE"; 55 | attribute CAPACITANCE : string; 56 | attribute CAPACITANCE of clkin1_ibufg : label is "DONT_CARE"; 57 | attribute IBUF_DELAY_VALUE : string; 58 | attribute IBUF_DELAY_VALUE of clkin1_ibufg : label is "0"; 59 | attribute IFD_DELAY_VALUE : string; 60 | attribute IFD_DELAY_VALUE of clkin1_ibufg : label is "AUTO"; 61 | attribute BOX_TYPE of clkout1_buf : label is "PRIMITIVE"; 62 | attribute BOX_TYPE of clkout2_buf : label is "PRIMITIVE"; 63 | attribute BOX_TYPE of clkout3_buf : label is "PRIMITIVE"; 64 | attribute BOX_TYPE of clkout4_buf : label is "PRIMITIVE"; 65 | attribute BOX_TYPE of mmcm_adv_inst : label is "PRIMITIVE"; 66 | begin 67 | clkf_buf: unisim.vcomponents.BUFG 68 | port map ( 69 | I => clkfbout_clk_wiz_0, 70 | O => clkfbout_buf_clk_wiz_0 71 | ); 72 | clkin1_ibufg: unisim.vcomponents.IBUF 73 | generic map( 74 | IOSTANDARD => "DEFAULT" 75 | ) 76 | port map ( 77 | I => clk_in1, 78 | O => clk_in1_clk_wiz_0 79 | ); 80 | clkout1_buf: unisim.vcomponents.BUFG 81 | port map ( 82 | I => clk_24MHz_clk_wiz_0, 83 | O => clk_24MHz 84 | ); 85 | clkout2_buf: unisim.vcomponents.BUFG 86 | port map ( 87 | I => clk_25MHz_clk_wiz_0, 88 | O => clk_25MHz 89 | ); 90 | clkout3_buf: unisim.vcomponents.BUFG 91 | port map ( 92 | I => clk_250MHz_clk_wiz_0, 93 | O => clk_250MHz 94 | ); 95 | clkout4_buf: unisim.vcomponents.BUFG 96 | port map ( 97 | I => clk_PS_clk_wiz_0, 98 | O => clk_PS 99 | ); 100 | mmcm_adv_inst: unisim.vcomponents.MMCME2_ADV 101 | generic map( 102 | BANDWIDTH => "OPTIMIZED", 103 | CLKFBOUT_MULT_F => 6.000000, 104 | CLKFBOUT_PHASE => 0.000000, 105 | CLKFBOUT_USE_FINE_PS => false, 106 | CLKIN1_PERIOD => 8.000000, 107 | CLKIN2_PERIOD => 0.000000, 108 | CLKOUT0_DIVIDE_F => 31.250000, 109 | CLKOUT0_DUTY_CYCLE => 0.500000, 110 | CLKOUT0_PHASE => 0.000000, 111 | CLKOUT0_USE_FINE_PS => false, 112 | CLKOUT1_DIVIDE => 30, 113 | CLKOUT1_DUTY_CYCLE => 0.500000, 114 | CLKOUT1_PHASE => 0.000000, 115 | CLKOUT1_USE_FINE_PS => false, 116 | CLKOUT2_DIVIDE => 3, 117 | CLKOUT2_DUTY_CYCLE => 0.500000, 118 | CLKOUT2_PHASE => 0.000000, 119 | CLKOUT2_USE_FINE_PS => false, 120 | CLKOUT3_DIVIDE => 5, 121 | CLKOUT3_DUTY_CYCLE => 0.500000, 122 | CLKOUT3_PHASE => 0.000000, 123 | CLKOUT3_USE_FINE_PS => false, 124 | CLKOUT4_CASCADE => false, 125 | CLKOUT4_DIVIDE => 1, 126 | CLKOUT4_DUTY_CYCLE => 0.500000, 127 | CLKOUT4_PHASE => 0.000000, 128 | CLKOUT4_USE_FINE_PS => false, 129 | CLKOUT5_DIVIDE => 1, 130 | CLKOUT5_DUTY_CYCLE => 0.500000, 131 | CLKOUT5_PHASE => 0.000000, 132 | CLKOUT5_USE_FINE_PS => false, 133 | CLKOUT6_DIVIDE => 1, 134 | CLKOUT6_DUTY_CYCLE => 0.500000, 135 | CLKOUT6_PHASE => 0.000000, 136 | CLKOUT6_USE_FINE_PS => false, 137 | COMPENSATION => "ZHOLD", 138 | DIVCLK_DIVIDE => 1, 139 | IS_CLKINSEL_INVERTED => '0', 140 | IS_PSEN_INVERTED => '0', 141 | IS_PSINCDEC_INVERTED => '0', 142 | IS_PWRDWN_INVERTED => '0', 143 | IS_RST_INVERTED => '0', 144 | REF_JITTER1 => 0.010000, 145 | REF_JITTER2 => 0.010000, 146 | SS_EN => "FALSE", 147 | SS_MODE => "CENTER_HIGH", 148 | SS_MOD_PERIOD => 10000, 149 | STARTUP_WAIT => false 150 | ) 151 | port map ( 152 | CLKFBIN => clkfbout_buf_clk_wiz_0, 153 | CLKFBOUT => clkfbout_clk_wiz_0, 154 | CLKFBOUTB => NLW_mmcm_adv_inst_CLKFBOUTB_UNCONNECTED, 155 | CLKFBSTOPPED => NLW_mmcm_adv_inst_CLKFBSTOPPED_UNCONNECTED, 156 | CLKIN1 => clk_in1_clk_wiz_0, 157 | CLKIN2 => '0', 158 | CLKINSEL => '1', 159 | CLKINSTOPPED => NLW_mmcm_adv_inst_CLKINSTOPPED_UNCONNECTED, 160 | CLKOUT0 => clk_24MHz_clk_wiz_0, 161 | CLKOUT0B => NLW_mmcm_adv_inst_CLKOUT0B_UNCONNECTED, 162 | CLKOUT1 => clk_25MHz_clk_wiz_0, 163 | CLKOUT1B => NLW_mmcm_adv_inst_CLKOUT1B_UNCONNECTED, 164 | CLKOUT2 => clk_250MHz_clk_wiz_0, 165 | CLKOUT2B => NLW_mmcm_adv_inst_CLKOUT2B_UNCONNECTED, 166 | CLKOUT3 => clk_PS_clk_wiz_0, 167 | CLKOUT3B => NLW_mmcm_adv_inst_CLKOUT3B_UNCONNECTED, 168 | CLKOUT4 => NLW_mmcm_adv_inst_CLKOUT4_UNCONNECTED, 169 | CLKOUT5 => NLW_mmcm_adv_inst_CLKOUT5_UNCONNECTED, 170 | CLKOUT6 => NLW_mmcm_adv_inst_CLKOUT6_UNCONNECTED, 171 | DADDR(6 downto 0) => B"0000000", 172 | DCLK => '0', 173 | DEN => '0', 174 | DI(15 downto 0) => B"0000000000000000", 175 | DO(15 downto 0) => NLW_mmcm_adv_inst_DO_UNCONNECTED(15 downto 0), 176 | DRDY => NLW_mmcm_adv_inst_DRDY_UNCONNECTED, 177 | DWE => '0', 178 | LOCKED => NLW_mmcm_adv_inst_LOCKED_UNCONNECTED, 179 | PSCLK => '0', 180 | PSDONE => NLW_mmcm_adv_inst_PSDONE_UNCONNECTED, 181 | PSEN => '0', 182 | PSINCDEC => '0', 183 | PWRDWN => '0', 184 | RST => reset 185 | ); 186 | end STRUCTURE; 187 | library IEEE; 188 | use IEEE.STD_LOGIC_1164.ALL; 189 | library UNISIM; 190 | use UNISIM.VCOMPONENTS.ALL; 191 | entity clk_wiz_0 is 192 | port ( 193 | clk_24MHz : out STD_LOGIC; 194 | clk_25MHz : out STD_LOGIC; 195 | clk_250MHz : out STD_LOGIC; 196 | clk_PS : out STD_LOGIC; 197 | reset : in STD_LOGIC; 198 | clk_in1 : in STD_LOGIC 199 | ); 200 | attribute NotValidForBitStream : boolean; 201 | attribute NotValidForBitStream of clk_wiz_0 : entity is true; 202 | end clk_wiz_0; 203 | 204 | architecture STRUCTURE of clk_wiz_0 is 205 | begin 206 | inst: entity work.clk_wiz_0_clk_wiz_0_clk_wiz 207 | port map ( 208 | clk_24MHz => clk_24MHz, 209 | clk_250MHz => clk_250MHz, 210 | clk_25MHz => clk_25MHz, 211 | clk_PS => clk_PS, 212 | clk_in1 => clk_in1, 213 | reset => reset 214 | ); 215 | end STRUCTURE; 216 | -------------------------------------------------------------------------------- /ip/clk_wiz_0/clk_wiz_0_stub.v: -------------------------------------------------------------------------------- 1 | // Copyright 1986-2020 Xilinx, Inc. All Rights Reserved. 2 | // -------------------------------------------------------------------------------- 3 | // Tool Version: Vivado v.2020.2 (win64) Build 3064766 Wed Nov 18 09:12:45 MST 2020 4 | // Date : Sun Sep 19 19:53:33 2021 5 | // Host : DESKTOP-MB5IJCE running 64-bit major release (build 9200) 6 | // Command : write_verilog -force -mode synth_stub 7 | // c:/Users/work/Documents/repos/Edge-Detection/ip/clk_wiz_0/clk_wiz_0_stub.v 8 | // Design : clk_wiz_0 9 | // Purpose : Stub declaration of top-level module interface 10 | // Device : xc7z020clg400-1 11 | // -------------------------------------------------------------------------------- 12 | 13 | // This empty module with port declaration file causes synthesis tools to infer a black box for IP. 14 | // The synthesis directives are for Synopsys Synplify support to prevent IO buffer insertion. 15 | // Please paste the declaration into a Verilog source file or add the file as an additional source. 16 | module clk_wiz_0(clk_24MHz, clk_25MHz, clk_250MHz, clk_PS, reset, 17 | clk_in1) 18 | /* synthesis syn_black_box black_box_pad_pin="clk_24MHz,clk_25MHz,clk_250MHz,clk_PS,reset,clk_in1" */; 19 | output clk_24MHz; 20 | output clk_25MHz; 21 | output clk_250MHz; 22 | output clk_PS; 23 | input reset; 24 | input clk_in1; 25 | endmodule 26 | -------------------------------------------------------------------------------- /ip/clk_wiz_0/clk_wiz_0_stub.vhdl: -------------------------------------------------------------------------------- 1 | -- Copyright 1986-2020 Xilinx, Inc. All Rights Reserved. 2 | -- -------------------------------------------------------------------------------- 3 | -- Tool Version: Vivado v.2020.2 (win64) Build 3064766 Wed Nov 18 09:12:45 MST 2020 4 | -- Date : Sun Sep 19 19:53:33 2021 5 | -- Host : DESKTOP-MB5IJCE running 64-bit major release (build 9200) 6 | -- Command : write_vhdl -force -mode synth_stub 7 | -- c:/Users/work/Documents/repos/Edge-Detection/ip/clk_wiz_0/clk_wiz_0_stub.vhdl 8 | -- Design : clk_wiz_0 9 | -- Purpose : Stub declaration of top-level module interface 10 | -- Device : xc7z020clg400-1 11 | -- -------------------------------------------------------------------------------- 12 | library IEEE; 13 | use IEEE.STD_LOGIC_1164.ALL; 14 | 15 | entity clk_wiz_0 is 16 | Port ( 17 | clk_24MHz : out STD_LOGIC; 18 | clk_25MHz : out STD_LOGIC; 19 | clk_250MHz : out STD_LOGIC; 20 | clk_PS : out STD_LOGIC; 21 | reset : in STD_LOGIC; 22 | clk_in1 : in STD_LOGIC 23 | ); 24 | 25 | end clk_wiz_0; 26 | 27 | architecture stub of clk_wiz_0 is 28 | attribute syn_black_box : boolean; 29 | attribute black_box_pad_pin : string; 30 | attribute syn_black_box of stub : architecture is true; 31 | attribute black_box_pad_pin of stub : architecture is "clk_24MHz,clk_25MHz,clk_250MHz,clk_PS,reset,clk_in1"; 32 | begin 33 | end; 34 | -------------------------------------------------------------------------------- /ip/clk_wiz_0/doc/clk_wiz_v6_0_changelog.txt: -------------------------------------------------------------------------------- 1 | 2020.2: 2 | * Version 6.0 (Rev. 6) 3 | * Bug Fix: Internal GUI fixes 4 | * Other: CR Fixes 5 | 6 | 2020.1.1: 7 | * Version 6.0 (Rev. 5) 8 | * No changes 9 | 10 | 2020.1: 11 | * Version 6.0 (Rev. 5) 12 | * Bug Fix: Internal GUI fixes 13 | * Other: CR Fixes 14 | 15 | 2019.2.2: 16 | * Version 6.0 (Rev. 4) 17 | * No changes 18 | 19 | 2019.2.1: 20 | * Version 6.0 (Rev. 4) 21 | * No changes 22 | 23 | 2019.2: 24 | * Version 6.0 (Rev. 4) 25 | * Bug Fix: Internal GUI fixes 26 | * Other: CR Fixes 27 | 28 | 2019.1.3: 29 | * Version 6.0 (Rev. 3) 30 | * No changes 31 | 32 | 2019.1.2: 33 | * Version 6.0 (Rev. 3) 34 | * No changes 35 | 36 | 2019.1.1: 37 | * Version 6.0 (Rev. 3) 38 | * No changes 39 | 40 | 2019.1: 41 | * Version 6.0 (Rev. 3) 42 | * Bug Fix: Internal GUI fixes 43 | * Other: New family support added 44 | 45 | 2018.3.1: 46 | * Version 6.0 (Rev. 2) 47 | * No changes 48 | 49 | 2018.3: 50 | * Version 6.0 (Rev. 2) 51 | * Bug Fix: Made input source independent for primary and secondary clock 52 | * Other: New family support added 53 | 54 | 2018.2: 55 | * Version 6.0 (Rev. 1) 56 | * Bug Fix: Removed vco freq check when Primitive is None 57 | * Other: New family support added 58 | 59 | 2018.1: 60 | * Version 6.0 61 | * Bug Fix: Bug fixes in Dynamic Reconfiguration feature and Write DRP feature 62 | * Bug Fix: Bug fixes for connection issue for s_axi_aresetn pin in IPI 63 | * Feature Enhancement: The default value of USE_PHASE_ALIGMENT is updated to false for UltraScale and UltraScale+ devices. Phase Alignment feature uses extra clock routes in UltraScale and UltraScale+ designs when MMCMs are used. These routing resources are wasted when user do not understand when phase alignment is really needed. Now, implementation tools can use these extra clock routing resources for high fanout signals. 64 | * Feature Enhancement: A column "Max. freq of buffer" is added in the Output Clock table which shows the maximum frequency that the selected output buffer can support 65 | * Other: DRCs added for invalid input values in Override mode 66 | 67 | 2017.4: 68 | * Version 5.4 (Rev. 3) 69 | * Bug Fix: Internal GUI issues are fixed for COMPENSATION mode as INTERNAL 70 | * Bug Fix: Fixed issue in dynamic reconfiguration of fractional values of M in MMCME3, MMCME4 71 | 72 | 2017.3: 73 | * Version 5.4 (Rev. 2) 74 | * General: Internal GUI changes. No effect on the customer design. Added support for aspartan7 devices 75 | 76 | 2017.2: 77 | * Version 5.4 (Rev. 1) 78 | * General: Internal GUI changes. No effect on the customer design. 79 | 80 | 2017.1: 81 | * Version 5.4 82 | * Port Change: Minor version upgrade. CLR pins are added to the pin list when selected buffer is BUFGCEDIV for ultrascale and ultrascale plus devices. 83 | * Other: Added support for new zynq ultrascale plus devices. 84 | 85 | 2016.4: 86 | * Version 5.3 (Rev. 3) 87 | * Bug Fix: Internal GUI issues are fixed. 88 | 89 | 2016.3: 90 | * Version 5.3 (Rev. 2) 91 | * Feature Enhancement: Added new option "Auto" under PRIMITIVE selection for ultrascale and above devices. This option allows the Wizard to instantiate appropriate primitive for the user inputs. 92 | * Feature Enhancement: Added Matched Routing Option for better timing solutions. 93 | * Feature Enhancement: Options 'Buffer' and 'Buffer_with_CE' are added to the buffer selection list. 94 | * Other: Source HDL files are concatenated into a single file to speed up synthesis and simulation. No changes required by the user 95 | * Other: Added support for Spartan7 devices. 96 | 97 | 2016.2: 98 | * Version 5.3 (Rev. 1) 99 | * Internal register bit update, no effect on customer designs. 100 | 101 | 2016.1: 102 | * Version 5.3 103 | * Added Clock Monitor Feature as part of clocking wizard 104 | * DRP registers can be directly written through AXI without resource utilization 105 | * Changes to HDL library management to support Vivado IP simulation library 106 | 107 | 2015.4.2: 108 | * Version 5.2 (Rev. 1) 109 | * No changes 110 | 111 | 2015.4.1: 112 | * Version 5.2 (Rev. 1) 113 | * No changes 114 | 115 | 2015.4: 116 | * Version 5.2 (Rev. 1) 117 | * Internal device family change, no functional changes 118 | 119 | 2015.3: 120 | * Version 5.2 121 | * IP revision number added to HDL module, library, and include file names, to support designs with both locked and upgraded IP instances 122 | * Port Renaming tab is hidden in the GUI in IP Integrator as this feature is not supported 123 | * Phase alignment feature is removed for ultrascale PLL as primitve has limited capabilities of supporting this feature 124 | * When clocking wizard is targetted on a board part, the frequency values that gets propagated to primary and secondary clocks are displayed in floating number format 125 | * Example design and simulation files are delivered in verilog only 126 | 127 | 2015.2.1: 128 | * Version 5.1 (Rev. 6) 129 | * No changes 130 | 131 | 2015.2: 132 | * Version 5.1 (Rev. 6) 133 | * No changes 134 | 135 | 2015.1: 136 | * Version 5.1 (Rev. 6) 137 | * Updated mmcm_pll_filter_lookup and mmcm_pll_lock_lookup functions in the header file for 7-Series and UltraScale devices 138 | * Supported devices and production status are now determined automatically, to simplify support for future devices 139 | 140 | 2014.4.1: 141 | * Version 5.1 (Rev. 5) 142 | * No changes 143 | 144 | 2014.4: 145 | * Version 5.1 (Rev. 5) 146 | * Internal device family change, no functional changes 147 | * updates related to the source selection based on board interface for zed board 148 | 149 | 2014.3: 150 | * Version 5.1 (Rev. 4) 151 | * Option added to enable dynamic phase and duty cycle for resource optimization in AXI4-Lite interface 152 | 153 | 2014.2: 154 | * Version 5.1 (Rev. 3) 155 | * Updated for AXI4-Lite interface locked status register address and bit mapping to align with the pg065 156 | 157 | 2014.1: 158 | * Version 5.1 (Rev. 2) 159 | * Updated to use inverted output CLKOUTB 0-3 of Clocking Primitive based on requested 180 phase w.r.t. previous clock 160 | * Internal device family name change, no functional changes 161 | 162 | 2013.4: 163 | * Version 5.1 (Rev. 1) 164 | * Added support for Ultrascale devices 165 | * Updated Board Flow GUI to select the clock interfaces 166 | * Fixed issue with Stub file parameter error for BUFR output driver 167 | 168 | 2013.3: 169 | * Version 5.1 170 | * Added AXI4-Lite interface to dynamically reconfigure MMCM/PLL 171 | * Improved safe clock logic to remove glitches on clock outputs for odd multiples of input clock frequencies 172 | * Fixed precision issues between displayed and actual frequencies 173 | * Added tool tips to GUI 174 | * Added Jitter and Phase error values to IP properties 175 | * Added support for Cadence IES and Synopsys VCS simulators 176 | * Reduced warnings in synthesis and simulation 177 | * Enhanced support for IP Integrator 178 | 179 | 2013.2: 180 | * Version 5.0 (Rev. 1) 181 | * Fixed issue with clock constraints for multiple instances of clocking wizard 182 | * Updated Life-Cycle status of devices 183 | 184 | 2013.1: 185 | * Version 5.0 186 | * Lower case ports for Verilog 187 | * Added Safe Clock Startup and Clock Sequencing 188 | 189 | (c) Copyright 2008 - 2020 Xilinx, Inc. All rights reserved. 190 | 191 | This file contains confidential and proprietary information 192 | of Xilinx, Inc. and is protected under U.S. and 193 | international copyright and other intellectual property 194 | laws. 195 | 196 | DISCLAIMER 197 | This disclaimer is not a license and does not grant any 198 | rights to the materials distributed herewith. Except as 199 | otherwise provided in a valid license issued to you by 200 | Xilinx, and to the maximum extent permitted by applicable 201 | law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND 202 | WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES 203 | AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING 204 | BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- 205 | INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and 206 | (2) Xilinx shall not be liable (whether in contract or tort, 207 | including negligence, or under any other theory of 208 | liability) for any loss or damage of any kind or nature 209 | related to, arising under or in connection with these 210 | materials, including for any direct, or any indirect, 211 | special, incidental, or consequential loss or damage 212 | (including loss of data, profits, goodwill, or any type of 213 | loss or damage suffered as a result of any action brought 214 | by a third party) even if such damage or loss was 215 | reasonably foreseeable or Xilinx had been advised of the 216 | possibility of the same. 217 | 218 | CRITICAL APPLICATIONS 219 | Xilinx products are not designed or intended to be fail- 220 | safe, or for use in any application requiring fail-safe 221 | performance, such as life-support or safety devices or 222 | systems, Class III medical devices, nuclear facilities, 223 | applications related to the deployment of airbags, or any 224 | other applications that could lead to death, personal 225 | injury, or severe property or environmental damage 226 | (individually and collectively, "Critical 227 | Applications"). Customer assumes the sole risk and 228 | liability of any use of Xilinx products in Critical 229 | Applications, subject only to applicable laws and 230 | regulations governing limitations on product liability. 231 | 232 | THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS 233 | PART OF THIS FILE AT ALL TIMES. 234 | -------------------------------------------------------------------------------- /rtl/HDMI_TMDS.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 03/23/2021 03:25:14 PM 7 | // Design Name: 8 | // Module Name: TMDS_2 9 | // Project Name: 10 | // Target Devices: 11 | // Tool Versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // open sourced, see google drive for TMDS algorithm flowchart 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | 23 | module TMDS_encoder2 ( 24 | input clk, 25 | input Reset, 26 | input de, 27 | input [1:0] ctrl, 28 | input [7:0] din, 29 | output reg [9:0] dout 30 | ); 31 | 32 | wire [3:0] Nb1s; 33 | wire XNOR; 34 | wire [8:0] q_m; 35 | reg [3:0] balance_acc; 36 | wire [3:0] balance; 37 | wire balance_sign_eq; 38 | wire invert_q_m; 39 | wire [3:0] balance_acc_inc; 40 | wire [3:0] balance_acc_new; 41 | wire [9:0] TMDS_data; 42 | wire [9:0] TMDS_code; 43 | 44 | assign Nb1s = din[0] + din[1] + din[2] + din[3] + din[4] + din[5] + din[6] + din[7]; 45 | assign XNOR = (Nb1s>4'd4) || (Nb1s==4'd4 && din[0]==1'b0); 46 | assign q_m = {~XNOR, q_m[6:0] ^ din[7:1] ^ {7{XNOR}}, din[0]}; 47 | 48 | assign balance = q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7] - 4'd4; 49 | assign balance_sign_eq = (balance[3] == balance_acc[3]); 50 | assign invert_q_m = (balance==0 || balance_acc==0) ? ~q_m[8] : balance_sign_eq; 51 | 52 | assign balance_acc_inc = balance - ({q_m[8] ^ ~balance_sign_eq} & ~(balance==0 || balance_acc==0)); 53 | assign balance_acc_new = invert_q_m ? balance_acc-balance_acc_inc : balance_acc+balance_acc_inc; 54 | assign TMDS_data = {invert_q_m, q_m[8], q_m[7:0] ^ {8{invert_q_m}}}; 55 | assign TMDS_code = ctrl[1] ? (ctrl[0] ? 10'b1010101011 : 10'b0101010100) : (ctrl[0] ? 10'b0010101011 : 10'b1101010100); 56 | 57 | initial begin 58 | dout <= 0; 59 | balance_acc <= 0; 60 | end 61 | 62 | 63 | always@(posedge clk, posedge Reset) begin 64 | if(Reset == 1'b1) begin 65 | dout <= 0; 66 | balance_acc <= 0; 67 | end 68 | else begin 69 | dout <= de ? TMDS_data : TMDS_code; 70 | balance_acc <= de ? balance_acc_new:4'h0; 71 | end 72 | end 73 | 74 | endmodule -------------------------------------------------------------------------------- /rtl/HDMI_encode.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 03/16/2021 10:13:58 AM 7 | // Design Name: 8 | // Module Name: HDMI_TX 9 | // Project Name: 10 | // Target Devices: 11 | // Tool Versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | 23 | module HDMI_encode( 24 | input i_p_clk, 25 | input i_resetn, 26 | 27 | // 8-bit RGB in 28 | input [7:0] i_red, 29 | input [7:0] i_green, 30 | input [7:0] i_blue, 31 | 32 | // timing signals 33 | input i_vsync, 34 | input i_hsync, 35 | input i_active_area, 36 | 37 | // 10-bit TMDS-encoded RGB out 38 | output [9:0] o_tmds_red, 39 | output [9:0] o_tmds_green, 40 | output [9:0] o_tmds_blue 41 | ); 42 | 43 | // 44 | // 45 | // 46 | 47 | // Channel 0, i_red and Timing 48 | // -> timing signals encoded only on channel 0 49 | TMDS_encoder2 TMDS_CH0( 50 | .clk (i_p_clk ), 51 | .Reset (~i_resetn ), 52 | .de (i_active_area ), 53 | .ctrl ({i_vsync,i_hsync} ), 54 | .din (i_red ), 55 | .dout (o_tmds_red ) 56 | ); 57 | 58 | // Channel 1, i_green 59 | TMDS_encoder2 TMDS_CH1( 60 | .clk (i_p_clk ), 61 | .Reset (~i_resetn ), 62 | .de (i_active_area ), 63 | .ctrl (2'b0 ), 64 | .din (i_green ), 65 | .dout (o_tmds_green ) 66 | ); 67 | 68 | // Channel 2, i_blue 69 | TMDS_encoder2 TMDS_CH2( 70 | .clk (i_p_clk ), 71 | .Reset (~i_resetn ), 72 | .de (i_active_area ), 73 | .ctrl (2'b0 ), 74 | .din (i_blue ), 75 | .dout (o_tmds_blue ) 76 | ); 77 | 78 | endmodule 79 | -------------------------------------------------------------------------------- /rtl/HDMI_out.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 03/20/2021 06:14:01 PM 7 | // Design Name: 8 | // Module Name: HDMI_Out 9 | // Project Name: 10 | // Target Devices: 11 | // Tool Versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | 23 | module HDMI_out( 24 | input i_p_clk, 25 | input i_tmds_clk, 26 | input i_resetn, 27 | 28 | input [9:0] i_tmds_red, 29 | input [9:0] i_tmds_green, 30 | input [9:0] i_tmds_blue, 31 | 32 | 33 | output [3:0] o_TMDS_P, 34 | output [3:0] o_TMDS_N 35 | ); 36 | 37 | // =========================================================================== 38 | // Parameters, Registers, and Wires 39 | // =========================================================================== 40 | 41 | reg [9:0] SR_tmds_red; 42 | reg [9:0] SR_tmds_green; 43 | reg [9:0] SR_tmds_blue; 44 | reg shiftEnable; 45 | reg [3:0] tmds_counter; 46 | 47 | // =========================================================================== 48 | // Implementation 49 | // =========================================================================== 50 | initial begin 51 | SR_tmds_red <= 0; 52 | SR_tmds_green <= 0; 53 | SR_tmds_blue <= 0; 54 | shiftEnable <= 0; 55 | tmds_counter <= 0; 56 | end 57 | 58 | // shift registers synced to 250Mhz i_tmds_clk 59 | always@(posedge i_tmds_clk) begin 60 | if(!i_resetn) begin 61 | shiftEnable <= 0; 62 | SR_tmds_red <= 0; 63 | SR_tmds_green <= 0; 64 | SR_tmds_blue <= 0; 65 | tmds_counter <= 0; 66 | end 67 | else begin 68 | shiftEnable <= (tmds_counter == 4'd9); // shift after ten bits 69 | 70 | SR_tmds_red <= (shiftEnable) ? i_tmds_red : SR_tmds_red[9:1]; // shift out [0] of each SR on each clock 71 | SR_tmds_green <= (shiftEnable) ? i_tmds_green : SR_tmds_green[9:1]; 72 | SR_tmds_blue <= (shiftEnable) ? i_tmds_blue : SR_tmds_blue[9:1]; 73 | 74 | tmds_counter <= (tmds_counter == 4'd9) ? 4'd0 : tmds_counter + 1; // count up 75 | end 76 | end 77 | 78 | // =========================================================================== 79 | // Differential Output Buffers 80 | // =========================================================================== 81 | OBUFDS OBUFDS_Red( 82 | .I (SR_tmds_red[0]), 83 | .O (o_TMDS_P[0]), 84 | .OB (o_TMDS_N[0]) 85 | ); 86 | 87 | OBUFDS OBUFDS_Green( 88 | .I (SR_tmds_green[0]), 89 | .O (o_TMDS_P[1]), 90 | .OB (o_TMDS_N[1]) 91 | ); 92 | 93 | OBUFDS OBUFDS_Blue( 94 | .I (SR_tmds_blue[0]), 95 | .O (o_TMDS_P[2]), 96 | .OB (o_TMDS_N[2]) 97 | ); 98 | 99 | OBUFDS OBUFDS_Clk( 100 | .I (i_p_clk), 101 | .O (o_TMDS_P[3]), 102 | .OB (o_TMDS_N[3]) 103 | ); 104 | 105 | endmodule 106 | -------------------------------------------------------------------------------- /rtl/HDMI_top.v: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | /* 4 | **** INSTANTIATION TEMPLATE **** 5 | 6 | HDMI_top HDMI_i ( 7 | .i_p_clk (), // pixel clock 8 | .i_tmds_clk (), // 10x pixel clock 9 | .i_resetn (), // sync active low reset 10 | 11 | // 24-bit RGB 12 | .i_rgb (), // r[7:0], g[15:8], b[23:16] 13 | 14 | // VTC 15 | .i_vsync (), 16 | .i_hsync (), 17 | .i_active_area (), 18 | 19 | // HDMI interface 20 | .o_TMDS_P (), 21 | .o_TMDS_N () 22 | ); 23 | 24 | */ 25 | module HDMI_top 26 | ( 27 | input wire i_p_clk, 28 | input wire i_tmds_clk, 29 | input wire i_resetn, 30 | 31 | input wire [7:0] i_red, 32 | input wire [7:0] i_green, 33 | input wire [7:0] i_blue, 34 | 35 | input wire i_vsync, 36 | input wire i_hsync, 37 | input wire i_active_area, 38 | 39 | output wire [3:0] o_TMDS_P, 40 | output wire [3:0] o_TMDS_N 41 | ); 42 | 43 | 44 | wire [9:0] channel_zero; 45 | wire [9:0] channel_one; 46 | wire [9:0] channel_two; 47 | 48 | HDMI_encode encode_i ( 49 | .i_p_clk (i_p_clk ), 50 | .i_resetn (i_resetn ), 51 | 52 | .i_red (i_red ), 53 | .i_green (i_green ), 54 | .i_blue (i_blue ), 55 | 56 | .i_vsync (i_vsync ), 57 | .i_hsync (i_hsync ), 58 | .i_active_area (i_active_area ), 59 | 60 | .o_tmds_red (channel_zero ), 61 | .o_tmds_green (channel_one ), 62 | .o_tmds_blue (channel_two ) 63 | ); 64 | 65 | HDMI_out out_i ( 66 | .i_p_clk (i_p_clk ), 67 | .i_tmds_clk (i_tmds_clk ), 68 | .i_resetn (i_resetn ), 69 | 70 | .i_tmds_red (channel_zero ), 71 | .i_tmds_green (channel_one ), 72 | .i_tmds_blue (channel_two ), 73 | 74 | .o_TMDS_P (o_TMDS_P ), 75 | .o_TMDS_N (o_TMDS_N ) 76 | ); 77 | 78 | 79 | endmodule -------------------------------------------------------------------------------- /rtl/cam_capture.v: -------------------------------------------------------------------------------- 1 | // capture.v 2 | // 3 | // This module captures incoming pixel data and is synchronous to the 4 | // 24 MHz clock generated by the XCLK pin of the OV7670 camera. 5 | // 6 | // The OV7670 outputs 30FPS in VGA. 7 | // 8 | module capture 9 | ( 10 | input wire i_pclk, // 24 MHz; sourced from OV7670 camera 11 | input wire i_rstn, // synchronous active low reset 12 | input wire i_cfg_done, // cam config done flag 13 | output wire o_status, // asserted when capturing 14 | 15 | // OV7670 camera interface 16 | input wire i_vsync, // active-high, indicates start of frame 17 | input wire i_href, // active-high, indicates row data transmission 18 | input wire [7:0] i_data, // pixel data from camera 19 | 20 | // FIFO write interface 21 | output reg o_wr, // fifo write enable 22 | output reg [11:0] o_wdata, // fifo write data; {red, green, blue} 23 | 24 | output wire o_sof // start of frame flag 25 | ); 26 | 27 | reg nxt_wr; 28 | reg [11:0] nxt_wdata; 29 | reg [7:0] byte1_data, nxt_byte1_data; 30 | 31 | reg pixel_half, nxt_pixel_half; 32 | 33 | reg [1:0] STATE, NEXT_STATE; 34 | localparam STATE_IDLE = 0, 35 | STATE_ACTIVE = 1, 36 | STATE_INITIAL = 2; 37 | 38 | initial begin 39 | o_wr = 0; 40 | STATE = STATE_INITIAL; 41 | end 42 | assign o_status = (STATE == STATE_ACTIVE); 43 | 44 | reg vsync1, vsync2; 45 | wire vsync_posedge; 46 | 47 | // **** vsync negedge detector **** 48 | // 49 | always@(posedge i_pclk) begin 50 | if(!i_rstn) begin 51 | {vsync1, vsync2} <= 2'b0; 52 | end 53 | else begin 54 | {vsync1, vsync2} <= {i_vsync, vsync1}; 55 | end 56 | end 57 | assign o_sof = ((vsync1 == 0) && (vsync2 == 1)); // vsync negedge 58 | assign vsync_posedge = ((vsync1 == 1) && (vsync2 == 0)); 59 | 60 | // **** Next State Logic **** 61 | // 62 | always@* begin 63 | nxt_wr = 0; 64 | nxt_wdata = o_wdata; 65 | nxt_byte1_data = byte1_data; 66 | nxt_pixel_half = pixel_half; 67 | NEXT_STATE = STATE; 68 | 69 | case(STATE) 70 | 71 | STATE_INITIAL: begin 72 | NEXT_STATE = (i_cfg_done && o_sof) ? STATE_IDLE : STATE_INITIAL; 73 | end 74 | 75 | // camera not outputting 76 | STATE_IDLE: begin 77 | nxt_wr = 0; 78 | nxt_pixel_half = 1; 79 | NEXT_STATE = (o_sof) ? STATE_ACTIVE : STATE_IDLE; 80 | end 81 | 82 | // camera outputting display data 83 | STATE_ACTIVE: begin 84 | if(i_href) begin 85 | nxt_pixel_half = ~nxt_pixel_half; 86 | 87 | // RGB444: Second Byte (green, blue) 88 | if(pixel_half) begin 89 | nxt_wr = 1; 90 | nxt_wdata = {byte1_data[3:0], i_data}; 91 | end 92 | 93 | // RGB444: First Byte (red) 94 | else begin 95 | nxt_wr = 0; 96 | nxt_byte1_data[3:0] = i_data[3:0]; 97 | end 98 | end 99 | NEXT_STATE = (vsync_posedge) ? STATE_IDLE : STATE_ACTIVE; 100 | end 101 | 102 | endcase 103 | end 104 | 105 | always@(posedge i_pclk) begin 106 | if(!i_rstn) begin 107 | o_wr <= 0; 108 | o_wdata <= 0; 109 | byte1_data <= 0; 110 | pixel_half <= 0; 111 | STATE <= STATE_INITIAL; 112 | end 113 | else begin 114 | o_wr <= nxt_wr; 115 | o_wdata <= nxt_wdata; 116 | byte1_data <= nxt_byte1_data; 117 | pixel_half <= nxt_pixel_half; 118 | STATE <= NEXT_STATE; 119 | end 120 | end 121 | 122 | endmodule 123 | -------------------------------------------------------------------------------- /rtl/cam_top.v: -------------------------------------------------------------------------------- 1 | // cam_top.v 2 | // 3 | // Encapsulates all camera-related modules into a single block. 4 | // 5 | module cam_top 6 | #(parameter T_CFG_CLK = 8) 7 | ( 8 | input wire i_cfg_clk, 9 | input wire i_rstn, 10 | 11 | // OV7670 I/O 12 | input wire i_cam_pclk, 13 | input wire i_cam_vsync, // active-high, indicates start of frame 14 | input wire i_cam_href, // active-high, indicates row data transmission 15 | input wire [7:0] i_cam_data, // pixel data from camera 16 | 17 | // i2c bidirectional pins 18 | input wire i_scl, 19 | input wire i_sda, 20 | output wire o_scl, 21 | output wire o_sda, 22 | 23 | // Output Buffer FIFO 24 | input wire i_obuf_rclk, 25 | input wire i_obuf_rstn, 26 | input wire i_obuf_rd, 27 | output wire [11:0] o_obuf_data, 28 | output wire o_obuf_empty, 29 | output wire o_obuf_almostempty, 30 | output wire [3:0] o_obuf_fill, 31 | 32 | // Configuration Control 33 | input wire i_cfg_init, // initialize cam registers to ROM 34 | output wire o_cfg_done, // config done flag 35 | 36 | // Status Outputs 37 | output wire o_sof // start of frame flag 38 | ); 39 | 40 | // ============================================================= 41 | // Parameters, Registers, and Wires 42 | // ============================================================= 43 | wire obuf_wr; 44 | wire [11:0] obuf_wdata; 45 | 46 | 47 | //============================================================== 48 | //--------------------------------------------------- 49 | // Camera Configuration Module: 50 | //--------------------------------------------------- 51 | cfg_interface 52 | #(.T_CLK(8) ) 53 | cfg_i ( 54 | .i_clk (i_cfg_clk ), 55 | .i_rstn (i_rstn ), // active-low sync reset 56 | 57 | // controls 58 | .o_done (o_cfg_done ), // done flag 59 | .i_start (i_cfg_init ), // initialize cam registers 60 | 61 | // i2c pins 62 | .i_scl (i_scl ), 63 | .i_sda (i_sda ), 64 | .o_scl (o_scl ), 65 | .o_sda (o_sda ) 66 | ); 67 | 68 | 69 | //--------------------------------------------------- 70 | // Pixel Data Capture Module: 71 | //--------------------------------------------------- 72 | capture capture_i ( 73 | .i_pclk (i_cam_pclk ), // camera pclk 74 | .i_rstn (i_rstn ), // active-low sync reset 75 | .i_cfg_done (o_cfg_done ), // config module done flag 76 | 77 | // Camera Interface 78 | .i_vsync (i_cam_vsync ), // vsync from camera 79 | .i_href (i_cam_href ), // href from camera 80 | .i_data (i_cam_data ), // 8-bit data 81 | 82 | // 24MHz to 125MHz FIFO Write interface 83 | .o_wr (obuf_wr ), // FIFO write enable 84 | .o_wdata (obuf_wdata ), // 12-bit RGB data 85 | 86 | .o_sof (o_sof ) 87 | ); 88 | 89 | //--------------------------------------------------- 90 | // Output FIFO: 91 | //--------------------------------------------------- 92 | fifo_async 93 | #(.DATA_WIDTH (12), 94 | .PTR_WIDTH (4), 95 | .ALMOSTFULL_OFFSET (2), 96 | .ALMOSTEMPTY_OFFSET (2) 97 | ) 98 | frontFIFO_i ( 99 | // write interface 100 | .i_wclk (i_cam_pclk ), // 24 MHz camera pclk 101 | .i_wrstn (i_rstn ), // active-low async reset (24MHz) 102 | .i_wr (obuf_wr ), // write enable 103 | .i_wdata (obuf_wdata ), // write data 104 | .o_wfull (), 105 | .o_walmostfull (), 106 | .o_wfill (), 107 | 108 | // read interface 109 | .i_rclk (i_obuf_rclk ), // read clock 110 | .i_rrstn (i_obuf_rstn ), // active-low async reset 111 | .i_rd (i_obuf_rd ), // read enable 112 | .o_rdata (o_obuf_data ), // read data 113 | .o_rempty (o_obuf_empty ), // empty flag 114 | .o_ralmostempty (o_obuf_almostempty ), // almost empty flag 115 | .o_rfill (o_obuf_fill ) // read-side fill level 116 | ); 117 | 118 | endmodule 119 | 120 | -------------------------------------------------------------------------------- /rtl/cfg_interface.v: -------------------------------------------------------------------------------- 1 | // module: cfg_interface.v 2 | // 3 | // This module reads from config_rom and initiates i2c_master writes. 4 | // It operates in the 125 MHz clock domain. 5 | // 6 | `default_nettype none 7 | // 8 | module cfg_interface 9 | #(parameter T_CLK = 8) 10 | ( 11 | input wire i_clk, // 125 MHz clock 12 | input wire i_rstn, 13 | // 14 | input wire i_start, 15 | output reg o_done, 16 | 17 | // i2c pins 18 | input wire i_scl, 19 | input wire i_sda, 20 | output wire o_scl, 21 | output wire o_sda 22 | ); 23 | 24 | // 25 | reg nxt_done; 26 | 27 | // ROM 28 | reg [7:0] rom_addr, nxt_rom_addr; 29 | wire [15:0] rom_data; 30 | 31 | // i2c master 32 | reg wr, nxt_wr; 33 | 34 | reg [7:0] reg_addr, nxt_reg_addr; 35 | reg [7:0] wdata, nxt_wdata; 36 | 37 | wire busy; 38 | 39 | // FSM 40 | reg [1:0] STATE, NEXT_STATE; 41 | localparam STATE_IDLE = 0, 42 | STATE_OP = 1, 43 | STATE_DONE = 2, 44 | STATE_TIMER = 3; 45 | 46 | 47 | localparam DELAY_VAL = 1_000_000/T_CLK - 2; // clks for 1ms delay 48 | localparam TIMER_WIDTH = $clog2(DELAY_VAL); 49 | 50 | reg [TIMER_WIDTH-1:0] timer, nxt_timer; 51 | 52 | // **** Initial Values **** 53 | // 54 | initial begin 55 | wr = 0; 56 | rom_addr = 0; 57 | nxt_done = 0; 58 | STATE = STATE_IDLE; 59 | end 60 | 61 | 62 | // **** Next State Logic **** 63 | // 64 | always@* begin 65 | nxt_rom_addr = rom_addr; 66 | nxt_wr = 0; 67 | nxt_reg_addr = reg_addr; 68 | nxt_wdata = wdata; 69 | nxt_done = o_done; 70 | nxt_timer = timer; 71 | NEXT_STATE = STATE; 72 | 73 | case(STATE) 74 | 75 | STATE_IDLE: begin 76 | nxt_rom_addr = 0; 77 | nxt_done = (i_start) ? 0:o_done; 78 | NEXT_STATE = (i_start) ? STATE_OP:STATE_IDLE; 79 | end 80 | 81 | STATE_OP: begin 82 | if(!busy) begin 83 | case(rom_data) 84 | 85 | // delay 86 | 16'hFF_F0: begin 87 | nxt_rom_addr = rom_addr + 1; 88 | nxt_timer = DELAY_VAL; 89 | NEXT_STATE = STATE_TIMER; 90 | end 91 | 92 | // end of ROM 93 | 16'hFF_FF: begin 94 | NEXT_STATE = STATE_DONE; 95 | end 96 | 97 | default: begin 98 | nxt_wr = 1; 99 | nxt_reg_addr = rom_data[15:8]; 100 | nxt_wdata = rom_data[7:0]; 101 | nxt_rom_addr = rom_addr + 1; 102 | nxt_timer = 0; 103 | NEXT_STATE = STATE_TIMER; 104 | end 105 | endcase 106 | end 107 | end 108 | 109 | STATE_DONE: begin 110 | nxt_done = 1; 111 | NEXT_STATE = STATE_IDLE; 112 | end 113 | 114 | STATE_TIMER: begin 115 | if(timer == 0) begin 116 | NEXT_STATE = STATE_OP; 117 | end 118 | else begin 119 | nxt_timer = timer - 1; 120 | end 121 | end 122 | endcase 123 | end 124 | 125 | // 126 | // 127 | always@(posedge i_clk) begin 128 | if(!i_rstn) begin 129 | rom_addr <= 0; 130 | wr <= 0; 131 | reg_addr <= 0; 132 | wdata <= 0; 133 | timer <= 0; 134 | o_done <= 0; 135 | STATE <= STATE_OP; 136 | end 137 | else begin 138 | rom_addr <= nxt_rom_addr; 139 | wr <= nxt_wr; 140 | reg_addr <= nxt_reg_addr; 141 | wdata <= nxt_wdata; 142 | timer <= nxt_timer; 143 | o_done <= nxt_done; 144 | STATE <= NEXT_STATE; 145 | end 146 | end 147 | 148 | // **** Submodule Instantiation **** 149 | // 150 | cfg_rom config_rom_i ( 151 | .i_clk (i_clk), 152 | .i_rstn (i_rstn), 153 | .i_addr (rom_addr), 154 | .o_data (rom_data) 155 | ); 156 | 157 | 158 | // SCCB is the same as i2c but no ACK/NACK 159 | cfg_i2c_master 160 | #( 161 | .T_CLK (T_CLK) 162 | ) 163 | i2c_master_i 164 | ( 165 | .i_clk (i_clk), // 100 MHz clock 166 | .i_rstn (i_rstn), // async active low rst 167 | 168 | // read/write control 169 | .i_wr (wr), // write enable 170 | .i_rd (1'b0), // read enable (not used) 171 | .i_slave_addr (7'h21), // 7-bit slave device addr 172 | .i_reg_addr (reg_addr), // 8-bit register addr 173 | .i_wdata (wdata), // 8-bit write data 174 | 175 | // read data out 176 | .o_rdata (), // 8-bit read data out 177 | 178 | // status signals 179 | .o_busy (busy), // if low; ready to accept new operation 180 | .o_rdata_valid (), // indicates o_rdata is valid 181 | .o_nack_slave (), // NACK on slave address frame 182 | .o_nack_addr (), // NACK on register address frame 183 | .o_nack_data (), // NACK on data frame 184 | 185 | // bidirectional i2c pins 186 | .i_scl (i_scl), 187 | .i_sda (i_sda), 188 | .o_scl (o_scl), 189 | .o_sda (o_sda) 190 | ); 191 | 192 | // 7'b0100001 193 | 194 | 195 | 196 | endmodule -------------------------------------------------------------------------------- /rtl/cfg_rom.v: -------------------------------------------------------------------------------- 1 | // module: cfg_rom.v 2 | // 3 | // Contains camera configuration. 1 cycle read delay. 4 | // Register values from: 5 | // -> https://github.com/westonb/OV7670-Verilog/blob/master/src/OV7670_config_rom.v 6 | // - edited for RGB444 instead of RGB565 7 | // 8 | // Key takeaway is that OV7670 is configured to RGB444 output 9 | // data frame format: 1) { x, x, x, x, R[0], R[1], R[2], R[3] } 10 | // 2) {G[0], G[1], G[2], G[3], B[0], B[1], B[2], B[3]} 11 | `default_nettype none 12 | // 13 | module cfg_rom 14 | ( 15 | input wire i_clk, 16 | input wire i_rstn, 17 | 18 | input wire [7:0] i_addr, 19 | output reg [15:0] o_data 20 | ); 21 | 22 | always@(posedge i_clk) begin 23 | if(!i_rstn) o_data <= 0; 24 | else begin 25 | case(i_addr) 26 | 0: o_data <= 16'h12_80; // reset 27 | 1: o_data <= 16'hFF_F0; // delay 1ms, hardcoded in camera_interface 28 | 2: o_data <= 16'h12_04; // COM7, set RGB color output 29 | 3: o_data <= 16'h11_00; // CLKRC PLL 1x multiplier 30 | 4: o_data <= 16'h0C_00; // COM3, default settings 31 | 5: o_data <= 16'h3E_00; // COM14, no scaling, normal pclock 32 | 6: o_data <= 16'h04_00; // COM1, disable CCIR656 33 | 7: o_data <= 16'h8c_02; // RGB444, RGB444, {xR} {GB} sequence 34 | 8: o_data <= 16'h40_d0; // COM15, RGB444, full output range 35 | 9: o_data <= 16'h3a_04; // TSLB set correct output data sequence (magic) 36 | 10: o_data <= 16'h14_18; // COM9 MAX AGC value x4 37 | 11: o_data <= 16'h4F_B3; // MTX1 all of these are magical matrix coefficients 38 | 12: o_data <= 16'h50_B3; // MTX2 39 | 13: o_data <= 16'h51_00; // MTX3 40 | 14: o_data <= 16'h52_3d; // MTX4 41 | 15: o_data <= 16'h53_A7; // MTX5 42 | 16: o_data <= 16'h54_E4; // MTX6 43 | 17: o_data <= 16'h58_9E; // MTXS 44 | 18: o_data <= 16'h3D_C0; // COM13 sets gamma enable, does not preserve reserved bits, may be wrong? 45 | 19: o_data <= 16'h17_14; // HSTART start high 8 bits 46 | 20: o_data <= 16'h18_02; // HSTOP stop high 8 bits //these kill the odd colored line 47 | 21: o_data <= 16'h32_80; // HREF edge offset 48 | 22: o_data <= 16'h19_03; // VSTART start high 8 bits 49 | 23: o_data <= 16'h1A_7B; // VSTOP stop high 8 bits 50 | 24: o_data <= 16'h03_0A; // VREF vsync edge offset 51 | 25: o_data <= 16'h0F_41; // COM6 reset timings 52 | 26: o_data <= 16'h1E_00; // MVFP disable mirror / flip //might have magic value of 03 53 | 27: o_data <= 16'h33_0B; // CHLF //magic value from the internet 54 | 28: o_data <= 16'h3C_78; // COM12 no HREF when VSYNC low 55 | 29: o_data <= 16'h69_00; // GFIX fix gain control 56 | 30: o_data <= 16'h74_00; // REG74 Digital gain control 57 | 31: o_data <= 16'hB0_84; // RSVD magic value from the internet *required* for good color 58 | 32: o_data <= 16'hB1_0c; // ABLC1 59 | 33: o_data <= 16'hB2_0e; // RSVD more magic internet values 60 | 34: o_data <= 16'hB3_80; // THL_ST 61 | //begin mystery scaling numbers 62 | 35: o_data <= 16'h70_3a; // SCALING_XSC 63 | 36: o_data <= 16'h71_35; // SCALING_YSC 64 | 37: o_data <= 16'h72_11; // SCALING_DCWCTR 65 | 38: o_data <= 16'h73_f0; // SCALING_PCLK_DIV 66 | //gamma curve values 67 | 39: o_data <= 16'ha2_02; // SCALING_PCLK_DELAY 68 | 40: o_data <= 16'h7a_20; // SLOP 69 | 41: o_data <= 16'h7b_10; // GAM1 70 | 42: o_data <= 16'h7c_1e; // GAM2 71 | 43: o_data <= 16'h7d_35; // GAM3 72 | 44: o_data <= 16'h7e_5a; // GAM4 73 | 45: o_data <= 16'h7f_69; // GAM5 74 | 46: o_data <= 16'h80_76; // GAM6 75 | 47: o_data <= 16'h81_80; // GAM7 76 | 48: o_data <= 16'h82_88; // GAM8 77 | 49: o_data <= 16'h83_8f; // GAM9 78 | 50: o_data <= 16'h84_96; // GAM10 79 | 51: o_data <= 16'h85_a3; // GAM11 80 | 52: o_data <= 16'h86_af; // GAM12 81 | 53: o_data <= 16'h87_c4; // GAM13 82 | 54: o_data <= 16'h88_d7; // GAM14 83 | //AGC and AEC 84 | 55: o_data <= 16'h89_e8; 85 | 56: o_data <= 16'h13_e0; // COM8, disable AGC / AEC 86 | 57: o_data <= 16'h00_00; // set gain reg to 0 for AGC 87 | 58: o_data <= 16'h10_00; // set ARCJ reg to 0 88 | 59: o_data <= 16'h0d_40; // magic reserved bit for COM4 89 | 60: o_data <= 16'h14_18; // COM9, 4x gain + magic bit 90 | 61: o_data <= 16'ha5_05; // BD50MAX 91 | 62: o_data <= 16'hab_07; // DB60MAX 92 | 63: o_data <= 16'h24_95; // AGC upper limit 93 | 64: o_data <= 16'h25_33; // AGC lower limit 94 | 65: o_data <= 16'h26_e3; // AGC/AEC fast mode op region 95 | 66: o_data <= 16'h9f_78; // HAECC1 96 | 67: o_data <= 16'ha0_68; // HAECC2 97 | 68: o_data <= 16'ha1_03; // magic 98 | 69: o_data <= 16'ha6_d8; // HAECC3 99 | 70: o_data <= 16'ha7_d8; // HAECC4 100 | 71: o_data <= 16'ha8_f0; // HAECC5 101 | 72: o_data <= 16'ha9_90; // HAECC6 102 | 73: o_data <= 16'haa_94; // HAECC7 103 | 74: o_data <= 16'h13_a7; // COM8, enable AGC / AEC 104 | 75: o_data <= 16'h1E_23; // mirror image 105 | //76: o_data <= 16'h70_80; // test pattern enable x 106 | //77: o_data <= 16'h71_FF; // test pattern enable y 107 | 76: o_data <= 16'h69_06; 108 | default: o_data <= 16'hFF_FF; //mark end of ROM 109 | endcase 110 | end 111 | end 112 | 113 | 114 | endmodule -------------------------------------------------------------------------------- /rtl/debounce.v: -------------------------------------------------------------------------------- 1 | // debounce module 2 | // -> 100 MHz 3 | // -> applies 20 ms debounce to input 4 | // 5 | 6 | module debounce 7 | ( 8 | input wire i_clk, 9 | input wire i_input, // input to be debounced 10 | 11 | output reg o_db // debounced 12 | ); 13 | 14 | // debounce period in clock periods 15 | parameter DB_COUNT = 2_000_000; 16 | 17 | reg [31:0] counter; 18 | 19 | reg r_input1; 20 | reg r_input2; 21 | 22 | initial begin 23 | r_input1 = 0; 24 | r_input2 = 0; 25 | o_db = 0; 26 | counter = 0; 27 | end 28 | 29 | // 30 | // double flop the input 31 | // 32 | always@(posedge i_clk) begin 33 | r_input1 <= i_input; 34 | r_input2 <= r_input1; 35 | end 36 | 37 | // 38 | // debounce logic 39 | // 40 | always@(posedge i_clk) begin 41 | if(r_input2 != o_db && counter < DB_COUNT) begin 42 | counter <= counter + 1; 43 | end 44 | else if(counter == DB_COUNT) begin 45 | o_db <= r_input2; 46 | counter <= 0; 47 | end 48 | else begin 49 | counter <= 0; 50 | end 51 | end 52 | 53 | endmodule // debounce -------------------------------------------------------------------------------- /rtl/display_interface.v: -------------------------------------------------------------------------------- 1 | module display_interface 2 | ( 3 | input wire i_p_clk, 4 | input wire i_tmds_clk, 5 | input wire i_rstn, 6 | input wire i_mode, 7 | 8 | // frame buffer interface 9 | output reg [18:0] o_raddr, 10 | input wire [11:0] i_rdata, 11 | 12 | // TMDS out 13 | output wire [3:0] o_TMDS_P, 14 | output wire [3:0] o_TMDS_N 15 | ); 16 | 17 | 18 | // ============================================================= 19 | // Parameters, Registers, and Wires 20 | // ============================================================= 21 | reg [18:0] nxt_raddr; 22 | 23 | wire vsync, hsync, active; 24 | wire [9:0] counterX, counterY; 25 | reg [7:0] red, green, blue; 26 | 27 | reg [1:0] STATE, NEXT_STATE; 28 | localparam STATE_INITIAL = 0, 29 | STATE_DELAY = 1, 30 | STATE_IDLE = 3, 31 | STATE_ACTIVE = 2; 32 | 33 | 34 | // ============================================================= 35 | // Implementation: 36 | // ============================================================= 37 | 38 | initial begin 39 | STATE = STATE_INITIAL; 40 | end 41 | 42 | // assign rgb based on mode; rgb or greyscale 43 | always@* begin 44 | if(i_mode) begin 45 | red = i_rdata; 46 | green = i_rdata; 47 | blue = i_rdata; 48 | end 49 | else begin 50 | red = {i_rdata[11:8], {4'hF} }; 51 | green = {i_rdata[7:4], {4'hF} }; 52 | blue = {i_rdata[3:0], {4'hF} }; 53 | end 54 | end 55 | 56 | // next state combo logic 57 | always@* begin 58 | nxt_raddr = o_raddr; 59 | NEXT_STATE = STATE; 60 | case(STATE) 61 | 62 | // wait 2 frames for camera configuration on reset/startup 63 | STATE_INITIAL: begin 64 | NEXT_STATE = ((counterX == 640) && (counterY == 480)) ? STATE_DELAY:STATE_INITIAL; 65 | end 66 | 67 | STATE_DELAY: begin 68 | NEXT_STATE = ((counterX == 640) && (counterY == 480)) ? STATE_ACTIVE:STATE_DELAY; 69 | end 70 | 71 | STATE_IDLE: begin 72 | if((counterX == 799)&&((counterY==524)||(counterY<480))) begin 73 | nxt_raddr = o_raddr + 1; 74 | NEXT_STATE = STATE_ACTIVE; 75 | end 76 | else if(counterY > 479) begin 77 | nxt_raddr = 0; 78 | end 79 | end 80 | 81 | // normal operation: begin reading from frame buffer at start of frame 82 | STATE_ACTIVE: begin 83 | if(active && (counterX < 639)) begin 84 | nxt_raddr = (o_raddr == 307199) ? 0:o_raddr+1; 85 | end 86 | else begin 87 | NEXT_STATE = STATE_IDLE; 88 | end 89 | end 90 | 91 | 92 | endcase 93 | end 94 | 95 | // registered logic 96 | always@(posedge i_p_clk) begin 97 | if(!i_rstn) begin 98 | o_raddr <= 0; 99 | //STATE <= STATE_INITIAL; 100 | STATE <= STATE_DELAY; 101 | end 102 | else begin 103 | o_raddr <= nxt_raddr; 104 | STATE <= NEXT_STATE; 105 | end 106 | end 107 | 108 | // 109 | // 110 | vtc #( 111 | .COUNTER_WIDTH(10) 112 | ) 113 | vtc_i ( 114 | .i_clk (i_p_clk ), // pixel clock 115 | .i_rstn (i_rstn ), 116 | 117 | // timing signals 118 | .o_vsync (vsync ), 119 | .o_hsync (hsync ), 120 | .o_active (active ), 121 | 122 | // counter passthrough 123 | .o_counterX (counterX ), 124 | .o_counterY (counterY ) 125 | ); 126 | 127 | HDMI_top HDMI_i ( 128 | .i_p_clk (i_p_clk ), // pixel clock 129 | .i_tmds_clk (i_tmds_clk ), // 10x pixel clock 130 | .i_resetn (i_rstn ), 131 | 132 | .i_red (red ), 133 | .i_green (green ), 134 | .i_blue (blue ), 135 | 136 | // Timing Signals in; from VTC 137 | .i_vsync (vsync ), 138 | .i_hsync (hsync ), 139 | .i_active_area (active ), 140 | 141 | // HDMI TMDS out 142 | .o_TMDS_P (o_TMDS_P ), 143 | .o_TMDS_N (o_TMDS_N ) 144 | ); 145 | 146 | endmodule -------------------------------------------------------------------------------- /rtl/fifo_sync.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | // 3 | // 4 | module fifo_sync 5 | #(parameter DATA_WIDTH = 8, 6 | parameter ADDR_WIDTH = 9, 7 | parameter ALMOSTFULL_OFFSET = 2, 8 | parameter ALMOSTEMPTY_OFFSET = 2 9 | ) 10 | ( 11 | input wire i_clk, 12 | input wire i_rstn, 13 | 14 | input wire i_wr, 15 | input wire [DATA_WIDTH-1:0] i_data, 16 | 17 | input wire i_rd, 18 | output reg [DATA_WIDTH-1:0] o_data, 19 | 20 | output reg [ADDR_WIDTH:0] o_fill, 21 | 22 | output wire o_full, 23 | output wire o_almostfull, 24 | output wire o_empty, 25 | output wire o_almostempty, 26 | 27 | output wire o_error 28 | ); 29 | 30 | localparam FIFO_DEPTH = (1< template from UG901 5 | // 6 | `default_nettype none 7 | // 8 | // 9 | module mem_bram 10 | #(parameter BRAM_WIDTH = 12, 11 | parameter BRAM_DEPTH = 16384) 12 | ( 13 | input wire i_wclk, 14 | input wire i_wportEn, 15 | input wire [$clog2(BRAM_DEPTH)-1:0] i_waddr, 16 | input wire [BRAM_WIDTH-1:0] i_wdata, 17 | input wire i_wr, 18 | 19 | input wire i_rclk, 20 | input wire i_rportEn, 21 | input wire [$clog2(BRAM_DEPTH)-1:0] i_raddr, 22 | output reg [BRAM_WIDTH-1:0] o_rdata 23 | ); 24 | 25 | reg [BRAM_WIDTH-1:0] mem [0:BRAM_DEPTH]; 26 | 27 | always@(posedge i_wclk) begin 28 | if(i_wportEn) begin 29 | if(i_wr) begin 30 | mem[i_waddr] <= i_wdata; 31 | end 32 | end 33 | end 34 | 35 | always@(posedge i_rclk) begin 36 | if(i_rportEn) begin 37 | o_rdata <= mem[i_raddr]; 38 | end 39 | end 40 | 41 | endmodule -------------------------------------------------------------------------------- /rtl/mem_interface.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | // 3 | // 4 | module mem_interface 5 | #( 6 | parameter DATA_WIDTH = 12, 7 | parameter FILL_WIDTH = 10, 8 | parameter BRAM_DEPTH = 307200 9 | ) 10 | ( 11 | input wire i_clk, // 125 MHz board clock 12 | input wire i_rstn, // sync active low reset 13 | input wire i_flush, 14 | 15 | // Input interface 16 | output reg o_rd, 17 | input wire [DATA_WIDTH-1:0] i_rdata, 18 | input wire i_almostempty, 19 | 20 | // Frame buffer output interface 21 | input wire i_rclk, 22 | input wire [18:0] i_raddr, 23 | output wire [DATA_WIDTH-1:0] o_rdata 24 | ); 25 | 26 | 27 | // ============================================================= 28 | // Parameters, Registers, and Wires 29 | // ============================================================= 30 | 31 | reg WSTATE, NEXT_WSTATE; 32 | localparam WSTATE_IDLE = 0, 33 | WSTATE_ACTIVE = 1; 34 | reg nxt_rd; 35 | reg [$clog2(BRAM_DEPTH)-1:0] nxt_mem_waddr, mem_waddr; 36 | reg nxt_mem_wr, mem_wr; 37 | reg [9:0] nxt_wCounter, wCounter; 38 | // 39 | // 40 | reg RSTATE, NEXT_RSTATE; 41 | localparam RSTATE_IDLE = 0, 42 | RSTATE_ACTIVE = 1; 43 | reg nxt3_wr, nxt2_wr, nxt_wr; 44 | reg [$clog2(BRAM_DEPTH)-1:0] nxt_mem_raddr, mem_raddr; 45 | reg req_q1, req_q2; 46 | 47 | 48 | // ============================================================= 49 | // Submodule Instantiation: 50 | // ============================================================= 51 | mem_bram 52 | #(.BRAM_DEPTH(BRAM_DEPTH)) 53 | mem_bram_i ( 54 | .i_wclk (i_clk ), 55 | .i_wportEn (1'b1 ), 56 | .i_waddr (mem_waddr ), // write address 57 | .i_wdata (i_rdata ), // write data 58 | .i_wr (mem_wr ), // write enable 59 | 60 | .i_rclk (i_rclk ), 61 | .i_rportEn (1'b1 ), 62 | .i_raddr (i_raddr ), // read address 63 | .o_rdata (o_rdata ) // read data 64 | ); 65 | 66 | // ============================================================= 67 | // Implementation: 68 | // ============================================================= 69 | 70 | //--------------------------------------------------- 71 | // Memory Write FSM: 72 | //--------------------------------------------------- 73 | initial WSTATE = WSTATE_IDLE; 74 | always@* begin 75 | nxt_rd = 0; 76 | nxt_mem_wr = 0; 77 | nxt_mem_waddr = mem_waddr; 78 | // 79 | NEXT_WSTATE = WSTATE; 80 | // 81 | case(WSTATE) 82 | 83 | WSTATE_IDLE: begin 84 | if(!i_almostempty) begin 85 | nxt_rd = 1; 86 | nxt_mem_wr = 1; 87 | NEXT_WSTATE = WSTATE_ACTIVE; 88 | end 89 | end 90 | 91 | WSTATE_ACTIVE: begin 92 | nxt_rd = (!i_almostempty); 93 | nxt_mem_wr = (!i_almostempty); 94 | nxt_mem_waddr = (mem_waddr == 307199) ? 0:mem_waddr+1; 95 | if(i_almostempty) begin 96 | NEXT_WSTATE = WSTATE_IDLE; 97 | end 98 | end 99 | endcase 100 | end 101 | 102 | always@(posedge i_clk) begin 103 | if(!i_rstn || i_flush) begin 104 | o_rd <= 0; 105 | mem_wr <= 0; 106 | mem_waddr <= 0; 107 | WSTATE <= WSTATE_IDLE; 108 | end 109 | else begin 110 | o_rd <= nxt_rd; 111 | mem_wr <= nxt_mem_wr; 112 | mem_waddr <= nxt_mem_waddr; 113 | WSTATE <= NEXT_WSTATE; 114 | end 115 | end 116 | 117 | endmodule -------------------------------------------------------------------------------- /rtl/pp_greyscale.v: -------------------------------------------------------------------------------- 1 | // module: ps_greyscale.v 2 | // 3 | // This module performs preprocessing as necessary depending on operating 4 | // mode of the system. 5 | // 6 | // This module muxes between two outputs. 7 | // -> in color mode, it acts as a passthrough for RGB data. 8 | // -> in process mode, it applies the greyscale algorithm to the RGB data. 9 | // 10 | // The greyscale algorithm utilizes the luminosity method, which weighs 11 | // each color component for a more accurate result. 12 | // y = 0.299*R + 0.587*G + 0.114*B 13 | // 14 | // Verilog does not support decimal points in numbers, single-precision 15 | // fixed-point multiplication is rather expensive. 16 | // 17 | // The algorithm is adapted to use bit-shifts instead, see docs/notes.txt: 18 | // -> y = [(R>>2) + (R>>5) + (R>>6)] + [(G>>1) + (G>>4) + (G>>5)] + (B>>3) 19 | // 20 | // This version of the algorithm is shown to have a negligible error, see 21 | // docs/greyscale.m 22 | // 23 | `default_nettype none 24 | // 25 | module pp_greyscale 26 | ( 27 | input wire i_clk, 28 | input wire i_rstn, 29 | 30 | // data in interface 31 | input wire i_valid, 32 | input wire [11:0] i_data, 33 | 34 | // Output interface 35 | output reg [11:0] o_data, 36 | output reg o_valid 37 | ); 38 | 39 | wire [7:0] r = {i_data[11:8], 4'b0}; 40 | wire [7:0] g = {i_data[7:4], 4'b0}; 41 | wire [7:0] b = {i_data[3:0], 4'b0}; 42 | 43 | initial o_valid = 0; 44 | 45 | always@(posedge i_clk) begin 46 | if(!i_rstn) begin 47 | o_data <= 0; 48 | o_valid <= 0; 49 | end 50 | else if(i_valid) begin 51 | o_valid <= 1; 52 | /* 53 | o_data <= {((r>>2) + (r>>5) + (r>>6) + 54 | (g>>1) + (g>>4) + (g>>5) + 55 | (b>>3)), 56 | 4'b0 // bottom 4 bits padded with 0s 57 | }; 58 | */ 59 | o_data <= (r>>2)+(r>>5)+(r>>6)+(g>>1)+(g>>4)+(g>>5)+(b>>3); 60 | end 61 | else begin 62 | o_valid <= 0; 63 | o_data <= 0; 64 | end 65 | end 66 | 67 | endmodule 68 | -------------------------------------------------------------------------------- /rtl/pp_preprocess.v: -------------------------------------------------------------------------------- 1 | // module: ps_preprocess.v 2 | // 3 | // This module is basically a wrapper for pp_greyscale. 4 | // 5 | // It includes read logic to get data from the camera capture FIFO and 6 | // passthrough logic for RGB display mode. 7 | // 8 | // It funnels the output of pp_greyscale into a synchronous FIFO and 9 | // sets a valid flag on reads based on whether there is available data. 10 | // The FIFO is necessary because the Gaussian module only reads in bursts of 11 | // one row at a time. 12 | // 13 | `default_nettype none 14 | // 15 | `define MODE_PASSTHROUGH 0 16 | // 17 | module pp_preprocess 18 | ( 19 | input wire i_clk, // input clock 20 | input wire i_rstn, // sync active low reset 21 | input wire i_flush, 22 | 23 | // Mode select 24 | input wire i_mode, // pretty much greyscale enable 25 | 26 | // Pixel Capture FIFO interface 27 | output reg o_rd, // read enable 28 | input wire [11:0] i_data, // input data (RGB444) 29 | input wire i_almostempty, 30 | 31 | // Output FIFO interface 32 | input wire i_rd, // read enable 33 | output wire [11:0] o_data, // output data 34 | output wire [10:0] o_fill, // 35 | output wire o_almostempty 36 | ); 37 | 38 | // Pixel Capture FIFO read 39 | reg [11:0] din; 40 | reg din_valid, nxt_din_valid; 41 | reg nxt_rd; 42 | reg [9:0] nxt_rdCounter, rdCounter; 43 | 44 | // greyscale signals 45 | wire gs_valid; 46 | wire [11:0] gs_dout; 47 | 48 | // Output FIFO 49 | reg fifo_wr; 50 | reg [11:0] fifo_wdata; 51 | wire [11:0] fifo_rdata; 52 | wire fifo_almostempty; 53 | wire fifo_almostfull; 54 | wire fifo_empty; 55 | 56 | // FSM 57 | reg STATE, NEXT_STATE; 58 | localparam STATE_IDLE = 0, 59 | STATE_ACTIVE = 1; 60 | initial STATE = STATE_IDLE; 61 | 62 | // greyscale converter 63 | pp_greyscale 64 | gscale_i ( 65 | .i_clk (i_clk ), 66 | .i_rstn (i_rstn ), 67 | 68 | .i_valid (din_valid ), 69 | .i_data (i_data ), 70 | 71 | .o_data (gs_dout ), 72 | .o_valid (gs_valid ) 73 | ); 74 | 75 | // output FIFO 76 | fifo_sync 77 | #(.DATA_WIDTH (12), 78 | .ADDR_WIDTH (10), 79 | .ALMOSTFULL_OFFSET (2), 80 | .ALMOSTEMPTY_OFFSET(1)) 81 | pp_obuf_i ( 82 | .i_clk (i_clk ), 83 | .i_rstn (i_rstn&&(~i_flush) ), 84 | 85 | .i_wr (fifo_wr ), 86 | .i_data (fifo_wdata ), 87 | 88 | .i_rd (i_rd ), 89 | .o_data (o_data ), 90 | 91 | .o_fill (o_fill ), 92 | 93 | .o_full (), 94 | .o_almostfull (fifo_almostfull ), 95 | .o_empty (fifo_empty ), 96 | .o_almostempty (o_almostempty ) 97 | ); 98 | 99 | 100 | // FSM next state logic for FIFO reads 101 | // 102 | always@* begin 103 | nxt_rd = 0; 104 | nxt_din_valid = 0; 105 | nxt_rdCounter = rdCounter; 106 | NEXT_STATE = STATE; 107 | 108 | case(STATE) 109 | 110 | STATE_IDLE: begin 111 | if(!i_almostempty) begin 112 | nxt_rd = 1; 113 | nxt_din_valid = 1; 114 | NEXT_STATE = STATE_ACTIVE; 115 | end 116 | end 117 | 118 | STATE_ACTIVE: begin 119 | nxt_rd = (!i_almostempty); 120 | nxt_din_valid = (!i_almostempty); 121 | if(i_almostempty) begin 122 | NEXT_STATE = STATE_IDLE; 123 | end 124 | end 125 | endcase 126 | end 127 | 128 | // FSM sync process 129 | // 130 | always@(posedge i_clk) begin 131 | if(!i_rstn) begin 132 | o_rd <= 0; 133 | din_valid <= 0; 134 | rdCounter <= 0; 135 | STATE <= STATE_IDLE; 136 | end 137 | else begin 138 | o_rd <= nxt_rd; 139 | din_valid <= nxt_din_valid; 140 | rdCounter <= nxt_rdCounter; 141 | STATE <= NEXT_STATE; 142 | end 143 | end 144 | 145 | 146 | // write to fifo based on mode 147 | // 148 | always@* begin 149 | if(i_mode == `MODE_PASSTHROUGH) begin 150 | fifo_wr = (!fifo_almostfull) ? din_valid : 0; 151 | fifo_wdata = i_data; 152 | end 153 | else begin 154 | fifo_wr = (!fifo_almostfull) ? gs_valid : 0; 155 | fifo_wdata = gs_dout; 156 | end 157 | end 158 | 159 | 160 | endmodule 161 | -------------------------------------------------------------------------------- /rtl/ps_gaussian.v: -------------------------------------------------------------------------------- 1 | module ps_gaussian 2 | ( 3 | input wire i_clk, // input clock 4 | input wire i_rstn, // sync active-low reset 5 | 6 | // kernel control interface 7 | input wire [23:0] i_r0_data, // three greyscale pixels from each row 8 | input wire [23:0] i_r1_data, 9 | input wire [23:0] i_r2_data, 10 | input wire i_valid, 11 | 12 | // output interface 13 | output reg [7:0] o_data, // 8-bit result 14 | output reg o_valid // valid flag 15 | ); 16 | 17 | integer i; 18 | 19 | // 3x3 kernel 20 | reg [7:0] kernel [8:0]; 21 | 22 | // stage 1: multiply 23 | wire [71:0] rowdata; 24 | reg [10:0] stage1_data [8:0]; 25 | reg stage1_valid; 26 | 27 | reg stage1_reg_valid; 28 | reg [10:0] stage1_data_reg [8:0]; 29 | 30 | 31 | // stage 2: accumulate 32 | reg [10:0] stage2_accumulator; 33 | reg [10:0] stage2_data; 34 | reg stage2_valid; 35 | 36 | // stage 3: divide by 16 37 | reg [10:0] stage3_data; 38 | reg stage3_valid; 39 | 40 | 41 | // KERNEL DEFINITION: 3X3 GAUSSIAN BLUR 42 | initial begin 43 | kernel[0] = 1; 44 | kernel[1] = 2; 45 | kernel[2] = 1; 46 | kernel[3] = 2; 47 | kernel[4] = 4; 48 | kernel[5] = 2; 49 | kernel[6] = 1; 50 | kernel[7] = 2; 51 | kernel[8] = 1; 52 | end 53 | 54 | // PIPELINE STAGE 1 (2 cycles) 55 | // 56 | assign rowdata = {i_r0_data, i_r1_data, i_r2_data}; 57 | 58 | // multiply pixel data by kernel 59 | always@(posedge i_clk) begin 60 | if(!i_rstn) begin 61 | stage1_valid <= 0; 62 | for(i=0; i<9; i=i+1) begin 63 | stage1_data[i] <= 0; 64 | end 65 | end 66 | else begin 67 | stage1_valid <= i_valid; 68 | for(i=0; i<9; i=i+1) begin 69 | stage1_data[i] <= $signed(kernel[i]) * 70 | $signed({1'b0, rowdata[i*8+:8]}); 71 | end 72 | end 73 | end 74 | 75 | // another register here for performance 76 | always@(posedge i_clk) begin 77 | if(!i_rstn) begin 78 | stage1_reg_valid <= 0; 79 | for(i=0; i<9; i=i+1) begin 80 | stage1_data_reg[i] <= 0; 81 | end 82 | end 83 | else begin 84 | stage1_reg_valid <= stage1_valid; 85 | for(i=0; i<9; i=i+1) begin 86 | stage1_data_reg[i] <= stage1_data[i]; 87 | end 88 | end 89 | end 90 | 91 | // PIPELINE STAGE 2 (1 cycle) 92 | // 93 | // sum all the stage 1 data 94 | always@* begin 95 | stage2_accumulator = 0; 96 | for(i=0; i<9; i=i+1) begin 97 | stage2_accumulator = $signed(stage2_accumulator) + 98 | $signed(stage1_data_reg[i]); 99 | end 100 | end 101 | 102 | // and register it 103 | always@(posedge i_clk) begin 104 | if(!i_rstn) begin 105 | stage2_valid <= 0; 106 | stage2_data <= 0; 107 | end 108 | else begin 109 | stage2_valid <= stage1_reg_valid; 110 | stage2_data <= stage2_accumulator; 111 | end 112 | end 113 | 114 | // PIPELINE STAGE 3 (1 cycle) 115 | // 116 | // divide by 16 and output 117 | always@(posedge i_clk) begin 118 | if(!i_rstn) begin 119 | o_valid <= 0; 120 | o_data <= 0; 121 | end 122 | else begin 123 | o_valid <= stage2_valid; 124 | o_data <= stage2_data >> 4; // stage2 is 11 bits, output is 8 bits 125 | end 126 | end 127 | 128 | 129 | endmodule -------------------------------------------------------------------------------- /rtl/ps_gaussian_top.v: -------------------------------------------------------------------------------- 1 | // module: ps_gaussian_top 2 | // 3 | // Wraps ps_kernel_control and ps_gaussian. 4 | // 5 | // Contains passthrough logic for when gaussian filter is disabled. 6 | // 7 | module ps_gaussian_top 8 | ( 9 | input wire i_clk, // input clock 10 | input wire i_rstn, // active low sync reset 11 | input wire i_enable, // filter enable 12 | input wire i_flush, 13 | 14 | input wire [11:0] i_data, // input data, RGB444 or greyscale[11:4] 15 | input wire i_almostempty, 16 | output reg o_rd, // 17 | 18 | input wire i_obuf_rd, 19 | output wire [11:0] o_obuf_data, 20 | output wire [4:0] o_obuf_fill, 21 | output wire o_obuf_full, 22 | output wire o_obuf_almostfull, 23 | output wire o_obuf_empty, 24 | output wire o_obuf_almostempty 25 | ); 26 | 27 | wire [23:0] r0_data, r1_data, r2_data; 28 | wire valid; 29 | wire req; 30 | wire [7:0] gaussian_dout; 31 | wire gaussian_valid; 32 | 33 | reg nxt_rd; 34 | reg nxt_din_valid, din_valid; 35 | reg [9:0] nxt_rdCounter, rdCounter; 36 | 37 | reg [11:0] obuf_wdata; 38 | reg obuf_wr; 39 | 40 | reg STATE, NEXT_STATE; 41 | localparam STATE_IDLE = 0, 42 | STATE_ACTIVE = 1; 43 | 44 | 45 | // FSM next state logic for FIFO reads 46 | // 47 | always@* begin 48 | nxt_rd = 0; 49 | nxt_din_valid = 0; 50 | NEXT_STATE = STATE; 51 | 52 | case(STATE) 53 | 54 | STATE_IDLE: begin 55 | case(i_enable) 56 | 0: begin 57 | if(!i_almostempty) begin 58 | nxt_rd = 1; 59 | nxt_din_valid = 1; 60 | NEXT_STATE = STATE_ACTIVE; 61 | end 62 | end 63 | 64 | 1: begin 65 | if(!i_almostempty && req) begin 66 | nxt_rd = 1; 67 | nxt_din_valid = 1; 68 | NEXT_STATE = STATE_ACTIVE; 69 | end 70 | end 71 | endcase 72 | end 73 | 74 | STATE_ACTIVE: begin 75 | case(i_enable) 76 | 0: begin 77 | nxt_rd = (!i_almostempty); 78 | nxt_din_valid = (!i_almostempty); 79 | NEXT_STATE = (i_almostempty) ? STATE_IDLE : STATE_ACTIVE; 80 | end 81 | 82 | 1: begin 83 | nxt_rd = (!i_almostempty && req); 84 | nxt_din_valid = (!i_almostempty && req); 85 | NEXT_STATE = (i_almostempty || !req) ? STATE_IDLE : STATE_ACTIVE; 86 | end 87 | endcase 88 | end 89 | 90 | endcase 91 | end 92 | 93 | // FSM sync process 94 | // 95 | always@(posedge i_clk) begin 96 | if(!i_rstn) begin 97 | o_rd <= 0; 98 | din_valid <= 0; 99 | rdCounter <= 0; 100 | STATE <= STATE_IDLE; 101 | end 102 | else begin 103 | o_rd <= nxt_rd; 104 | din_valid <= nxt_din_valid; 105 | rdCounter <= nxt_rdCounter; 106 | STATE <= NEXT_STATE; 107 | end 108 | end 109 | 110 | // passthrough logic 111 | always@* begin 112 | if(i_enable) begin 113 | obuf_wdata = {gaussian_dout, 4'b0}; 114 | obuf_wr = gaussian_valid; 115 | end 116 | else begin 117 | obuf_wdata = i_data; 118 | obuf_wr = din_valid; 119 | end 120 | end 121 | 122 | ps_kernel_control 123 | #(.LINE_LENGTH(640), 124 | .LINE_COUNT (480), 125 | .DATA_WIDTH (8)) 126 | gaus_ctrl_i ( 127 | .i_clk (i_clk ), 128 | .i_rstn (i_rstn&&(~i_flush) ), 129 | 130 | .i_data (i_data[11:4] ), 131 | .i_valid (din_valid ), 132 | .o_req (req ), 133 | 134 | .o_r0_data (r0_data ), 135 | .o_r1_data (r1_data ), 136 | .o_r2_data (r2_data ), 137 | .o_valid (valid ) 138 | ); 139 | 140 | ps_gaussian 141 | gaus_i ( 142 | .i_clk (i_clk ), 143 | .i_rstn (i_rstn&&(~i_flush) ), 144 | 145 | .i_r0_data (r0_data ), 146 | .i_r1_data (r1_data ), 147 | .i_r2_data (r2_data ), 148 | .i_valid (valid ), 149 | 150 | .o_data (gaussian_dout ), 151 | .o_valid (gaussian_valid ) 152 | ); 153 | 154 | fifo_sync 155 | #(.DATA_WIDTH (12), 156 | .ADDR_WIDTH (10), 157 | .ALMOSTFULL_OFFSET (2), 158 | .ALMOSTEMPTY_OFFSET(1)) 159 | ps_obuf_i ( 160 | .i_clk (i_clk), 161 | .i_rstn (i_rstn&&(~i_flush) ), 162 | 163 | .i_wr (obuf_wr), 164 | .i_data (obuf_wdata), 165 | 166 | .i_rd (i_obuf_rd), 167 | .o_data (o_obuf_data), 168 | 169 | .o_fill (o_obuf_fill), 170 | 171 | .o_full (o_obuf_full), 172 | .o_almostfull (o_obuf_almostfull), 173 | .o_empty (o_obuf_empty), 174 | .o_almostempty (o_obuf_almostempty) 175 | ); 176 | endmodule -------------------------------------------------------------------------------- /rtl/ps_kernel_control.v: -------------------------------------------------------------------------------- 1 | // module: ps_kernel_control 2 | // 3 | // This module stores incoming data in 4x line buffers. 4 | // 5 | // It reads three line buffers at a time and feeds that data 6 | // to the Gaussian block. 7 | // 8 | // The fourth line buffer is pre-loaded while the other three are 9 | // being read from. 10 | // 11 | // It also has a request flag that indicates it needs data to write 12 | // to the next line buffer. 13 | // 14 | module ps_kernel_control 15 | #( 16 | parameter LINE_LENGTH = 640, 17 | parameter LINE_COUNT = 480, 18 | parameter DATA_WIDTH = 8 19 | ) 20 | ( 21 | input wire i_clk, // input clock 22 | input wire i_rstn, // sync active low reset 23 | 24 | // Data in interface 25 | input wire [DATA_WIDTH-1:0] i_data, // 26 | input wire i_valid, // 27 | output reg o_req, // asserted when ready for more data 28 | 29 | // Gaussian MAC interface 30 | output reg [(3*DATA_WIDTH-1):0] o_r0_data, 31 | output reg [(3*DATA_WIDTH-1):0] o_r1_data, 32 | output reg [(3*DATA_WIDTH-1):0] o_r2_data, 33 | output reg o_valid 34 | ); 35 | 36 | // 37 | reg nxt_req; 38 | reg nxt_o_valid; 39 | 40 | // LINE BUFFER I/O 41 | reg [3:0] lineBuffer_wr; // line buffer write enables 42 | reg [3:0] lineBuffer_rd; // line buffer read enables 43 | // 44 | wire [(3*DATA_WIDTH-1):0] lB0_rdata; 45 | wire [(3*DATA_WIDTH-1):0] lB1_rdata; 46 | wire [(3*DATA_WIDTH-1):0] lB2_rdata; 47 | wire [(3*DATA_WIDTH-1):0] lB3_rdata; 48 | // 49 | reg [(3*DATA_WIDTH-1):0] lineBuffer0_rdata; 50 | reg [(3*DATA_WIDTH-1):0] lineBuffer1_rdata; 51 | reg [(3*DATA_WIDTH-1):0] lineBuffer2_rdata; 52 | reg [(3*DATA_WIDTH-1):0] lineBuffer3_rdata; 53 | 54 | 55 | // LINE BUFFER WRITE LOGIC 56 | reg [$clog2(LINE_LENGTH):0] w_pixelCounter; // counts pixels written to single buffer 57 | reg [1:0] w_lineBuffer_sel; // keeps track of buffer to write to 58 | 59 | // LINE BUFFER READ LOGIC 60 | // total fill level of all buffers 61 | reg [$clog2(3*LINE_LENGTH):0] r_fill; 62 | 63 | // counts pixels read from current buffer 64 | reg [$clog2(LINE_LENGTH):0] r_pixelCounter, 65 | nxt_r_pixelCounter; 66 | 67 | // counts # of lines processed 68 | reg [$clog2(LINE_COUNT):0] r_lineCounter, 69 | nxt_r_lineCounter; 70 | 71 | // overall buffer read enable 72 | reg r_lineBuffer_rd_en, nxt_r_lineBuffer_rd_en; 73 | 74 | 75 | // keeps track of 'target' read buffer 76 | reg [2:0] r_lineBuffer_sel, nxt_r_lineBuffer_sel; 77 | 78 | 79 | // FSM 80 | reg [1:0] RSTATE, NEXT_RSTATE; 81 | localparam RSTATE_IDLE = 0, 82 | RSTATE_PREFETCH = 1, 83 | RSTATE_ACTIVE = 2; 84 | 85 | // 86 | // LINE BUFFER WRITE LOGIC 87 | // 88 | // count every linebuffer write 89 | always@(posedge i_clk) begin 90 | if(!i_rstn) begin 91 | w_pixelCounter <= 0; 92 | end 93 | else begin 94 | if(i_valid) begin 95 | w_pixelCounter <= (w_pixelCounter == LINE_LENGTH-1) ? 0:w_pixelCounter+1; 96 | end 97 | end 98 | end 99 | 100 | // after writing a full line buffer, select the next line buffer 101 | always@(posedge i_clk) begin 102 | if(!i_rstn) begin 103 | w_lineBuffer_sel <= 0; 104 | end 105 | else begin 106 | if( (w_pixelCounter == LINE_LENGTH-1) && (i_valid)) begin 107 | if(w_lineBuffer_sel == 3) begin 108 | w_lineBuffer_sel <= 0; 109 | end 110 | else begin 111 | w_lineBuffer_sel <= w_lineBuffer_sel+1; 112 | end 113 | end 114 | end 115 | end 116 | 117 | // line buffer i/o 118 | always@* begin 119 | lineBuffer_wr = 0; 120 | lineBuffer_wr[w_lineBuffer_sel] = i_valid; 121 | end 122 | 123 | // 124 | // LINE BUFFER READ ENABLE LOGIC 125 | // 126 | // keep track of total # of pixels in line buffers 127 | always@(posedge i_clk) begin 128 | if(!i_rstn) begin 129 | r_fill <= 0; 130 | end 131 | else begin 132 | 133 | // write and not reading 134 | if(i_valid && !r_lineBuffer_rd_en) begin 135 | r_fill <= r_fill + 1; 136 | end 137 | 138 | // not writing and read 139 | else if(!i_valid && r_lineBuffer_rd_en) begin 140 | r_fill <= r_fill - 1; 141 | end 142 | end 143 | end 144 | 145 | 146 | 147 | // read from line buffers only when three lines are full 148 | always@* begin 149 | nxt_req = o_req; 150 | nxt_o_valid = r_lineBuffer_rd_en; 151 | nxt_r_lineBuffer_rd_en = 0; 152 | nxt_r_pixelCounter = r_pixelCounter; 153 | nxt_r_lineCounter = r_lineCounter; 154 | nxt_r_lineBuffer_sel = r_lineBuffer_sel; 155 | NEXT_RSTATE = RSTATE; 156 | 157 | case(RSTATE) 158 | 159 | // RSTATE_IDLE: 160 | // If there is 3 lines worth of pixel data present, 161 | // begin reading from line buffers 162 | RSTATE_IDLE: begin 163 | nxt_r_pixelCounter = 0; 164 | if(r_fill == (3*LINE_LENGTH)) begin 165 | nxt_req = 0; 166 | nxt_r_lineBuffer_rd_en = 1; 167 | NEXT_RSTATE = RSTATE_PREFETCH; 168 | end 169 | else begin 170 | nxt_req = 1; 171 | nxt_r_lineBuffer_rd_en = 0; 172 | end 173 | end 174 | 175 | // RSTATE_PREFETCH: 176 | // Account for total of 2 cycles of read latency for 177 | // the linebuffer reads 178 | RSTATE_PREFETCH: begin 179 | nxt_r_lineBuffer_rd_en = 1; 180 | NEXT_RSTATE = RSTATE_ACTIVE; 181 | end 182 | 183 | // RSTATE_ACTIVE: 184 | // If a line of pixels has been read: 185 | // - select next line buffer to read from 186 | // - request more data 187 | RSTATE_ACTIVE: begin 188 | nxt_r_pixelCounter = r_pixelCounter + 1; 189 | if(r_pixelCounter >= LINE_LENGTH-2) begin 190 | nxt_req = 1; 191 | nxt_r_lineBuffer_rd_en = 0; 192 | nxt_r_lineCounter = (r_lineCounter == LINE_COUNT-1) ? 0:r_lineCounter+1; 193 | nxt_r_lineBuffer_sel = (r_lineBuffer_sel == 3) ? 0:r_lineBuffer_sel+1; 194 | NEXT_RSTATE = RSTATE_IDLE; 195 | end 196 | else begin 197 | nxt_req = 0; 198 | nxt_r_lineBuffer_rd_en = 1; 199 | end 200 | end 201 | endcase 202 | end 203 | 204 | // registers 205 | always@(posedge i_clk) begin 206 | if(!i_rstn) begin 207 | o_req <= 0; 208 | o_valid <= 0; 209 | r_lineBuffer_rd_en <= 0; 210 | r_pixelCounter <= 0; 211 | r_lineCounter <= 0; 212 | r_lineBuffer_sel <= 0; 213 | RSTATE <= RSTATE_IDLE; 214 | end 215 | else begin 216 | o_req <= nxt_req; 217 | o_valid <= nxt_o_valid; 218 | r_lineBuffer_rd_en <= nxt_r_lineBuffer_rd_en; 219 | r_pixelCounter <= nxt_r_pixelCounter; 220 | r_lineCounter <= nxt_r_lineCounter; 221 | r_lineBuffer_sel <= nxt_r_lineBuffer_sel; 222 | RSTATE <= NEXT_RSTATE; 223 | end 224 | end 225 | 226 | // 227 | // LINE BUFFER READ SELECT LOGIC 228 | // 229 | // assign different data to outputs based on what current row is 230 | always@* begin 231 | lineBuffer_rd = {4{r_lineBuffer_rd_en}}; 232 | o_r0_data = 0; 233 | o_r1_data = 0; 234 | o_r2_data = 0; 235 | 236 | // first row of image 237 | if(r_lineCounter == 0) begin 238 | lineBuffer_rd[2] = 0; 239 | lineBuffer_rd[3] = 0; 240 | o_r0_data = lineBuffer0_rdata; 241 | o_r1_data = lineBuffer0_rdata; 242 | o_r2_data = lineBuffer1_rdata; 243 | end 244 | 245 | // last row of image 246 | 247 | else begin 248 | case(r_lineBuffer_sel) 249 | 250 | 0: begin 251 | lineBuffer_rd[2] = 0; 252 | o_r0_data = lineBuffer3_rdata; 253 | o_r1_data = lineBuffer0_rdata; 254 | o_r2_data = lineBuffer1_rdata; 255 | end 256 | 257 | 1: begin 258 | lineBuffer_rd[3] = 0; 259 | o_r0_data = lineBuffer0_rdata; 260 | o_r1_data = lineBuffer1_rdata; 261 | o_r2_data = lineBuffer2_rdata; 262 | end 263 | 264 | 2: begin 265 | lineBuffer_rd[0] = 0; 266 | o_r0_data = lineBuffer1_rdata; 267 | o_r1_data = lineBuffer2_rdata; 268 | o_r2_data = lineBuffer3_rdata; 269 | end 270 | 271 | 3: begin 272 | lineBuffer_rd[1] = 0; 273 | o_r0_data = lineBuffer2_rdata; 274 | o_r1_data = lineBuffer3_rdata; 275 | o_r2_data = lineBuffer0_rdata; 276 | end 277 | endcase 278 | end 279 | end 280 | 281 | localparam WORD3_INDEX = 2*DATA_WIDTH; 282 | 283 | // Output Combinatorial logic 284 | // assign different data to outputs based on what current column is 285 | always@* begin 286 | case(r_pixelCounter) 287 | default: begin 288 | lineBuffer0_rdata = lB0_rdata; 289 | lineBuffer1_rdata = lB1_rdata; 290 | lineBuffer2_rdata = lB2_rdata; 291 | lineBuffer3_rdata = lB3_rdata; 292 | end 293 | 294 | // catch the beginning of each row 295 | 0: begin 296 | lineBuffer0_rdata = { {2{lB0_rdata[DATA_WIDTH+:DATA_WIDTH]}}, 297 | lB0_rdata[0+:DATA_WIDTH]}; 298 | 299 | lineBuffer1_rdata = { {2{lB1_rdata[DATA_WIDTH+:DATA_WIDTH]}}, 300 | lB1_rdata[0+:DATA_WIDTH]}; 301 | 302 | lineBuffer2_rdata = { {2{lB2_rdata[DATA_WIDTH+:DATA_WIDTH]}}, 303 | lB2_rdata[0+:DATA_WIDTH]}; 304 | 305 | lineBuffer3_rdata = { {2{lB3_rdata[DATA_WIDTH+:DATA_WIDTH]}}, 306 | lB3_rdata[0+:DATA_WIDTH]}; 307 | end 308 | 309 | // catch end of each row 310 | (LINE_LENGTH-1): begin 311 | lineBuffer0_rdata = { lB0_rdata[(2*DATA_WIDTH)+:DATA_WIDTH], 312 | {2{lB0_rdata[DATA_WIDTH+:DATA_WIDTH]}} }; 313 | 314 | lineBuffer1_rdata = { lB1_rdata[(2*DATA_WIDTH)+:DATA_WIDTH], 315 | {2{lB1_rdata[DATA_WIDTH+:DATA_WIDTH]}} }; 316 | 317 | lineBuffer2_rdata = { lB2_rdata[(2*DATA_WIDTH)+:DATA_WIDTH], 318 | {2{lB2_rdata[DATA_WIDTH+:DATA_WIDTH]}} }; 319 | 320 | lineBuffer3_rdata = { lB3_rdata[(2*DATA_WIDTH)+:DATA_WIDTH], 321 | {2{lB3_rdata[DATA_WIDTH+:DATA_WIDTH]}} }; 322 | end 323 | endcase 324 | end 325 | 326 | ps_linebuffer 327 | #(.LINE_LENGTH(LINE_LENGTH), 328 | .DATA_WIDTH (DATA_WIDTH)) 329 | LINEBUF0_i ( 330 | .i_clk (i_clk ), 331 | .i_rstn (i_rstn ), // sync active low reset 332 | 333 | .i_wr (lineBuffer_wr[0] ), // write enable 334 | .i_wdata (i_data ), // 8-bit write data 335 | 336 | .i_rd (lineBuffer_rd[0] ), // read enable 337 | .o_rdata (lB0_rdata ) // 3 pixels of read data 338 | ); 339 | 340 | ps_linebuffer 341 | #(.LINE_LENGTH(LINE_LENGTH), 342 | .DATA_WIDTH (DATA_WIDTH)) 343 | LINEBUF1_i ( 344 | .i_clk (i_clk ), 345 | .i_rstn (i_rstn ), // sync active low reset 346 | 347 | .i_wr (lineBuffer_wr[1] ), // write enable 348 | .i_wdata (i_data ), // 8-bit write data 349 | 350 | .i_rd (lineBuffer_rd[1] ), // read enable 351 | .o_rdata (lB1_rdata ) // 3 pixels of read data 352 | ); 353 | 354 | ps_linebuffer 355 | #(.LINE_LENGTH(LINE_LENGTH), 356 | .DATA_WIDTH (DATA_WIDTH)) 357 | LINEBUF2_i ( 358 | .i_clk (i_clk ), 359 | .i_rstn (i_rstn ), // sync active low reset 360 | 361 | .i_wr (lineBuffer_wr[2] ), // write enable 362 | .i_wdata (i_data ), // 8-bit write data 363 | 364 | .i_rd (lineBuffer_rd[2] ), // read enable 365 | .o_rdata (lB2_rdata ) // 3 pixels of read data 366 | ); 367 | 368 | ps_linebuffer 369 | #(.LINE_LENGTH(LINE_LENGTH), 370 | .DATA_WIDTH (DATA_WIDTH)) 371 | LINEBUF3_i ( 372 | .i_clk (i_clk ), 373 | .i_rstn (i_rstn ), // sync active low reset 374 | 375 | .i_wr (lineBuffer_wr[3] ), // write enable 376 | .i_wdata (i_data ), // 8-bit write data 377 | 378 | .i_rd (lineBuffer_rd[3] ), // read enable 379 | .o_rdata (lB3_rdata ) // 3 pixels of read data 380 | ); 381 | 382 | 383 | endmodule -------------------------------------------------------------------------------- /rtl/ps_linebuffer.v: -------------------------------------------------------------------------------- 1 | // module: ps_linebuffer.v 2 | // 3 | // This is pretty much just a FIFO that outputs three 4 | // words per read. 5 | // 6 | // Should be synthesized as distributed ram w/ an output 7 | // buffer for better performance -> 1 cycle read latency 8 | // 9 | module ps_linebuffer 10 | #( 11 | parameter LINE_LENGTH = 640, 12 | parameter DATA_WIDTH = 8 13 | ) 14 | ( 15 | input wire i_clk, 16 | input wire i_rstn, 17 | 18 | // Write Interface 19 | input wire i_wr, 20 | input wire [DATA_WIDTH-1:0] i_wdata, 21 | 22 | // Read Interface 23 | input wire i_rd, 24 | output reg [3*DATA_WIDTH-1:0] o_rdata 25 | ); 26 | 27 | // 28 | reg [DATA_WIDTH-1:0] mem [LINE_LENGTH-1:0]; 29 | reg [3*DATA_WIDTH-1:0] rdata; 30 | 31 | reg [$clog2(LINE_LENGTH)-1:0] wptr, rptr; 32 | 33 | 34 | // infer distributed ram 35 | always@(posedge i_clk) begin 36 | if(i_wr) begin 37 | mem[wptr] <= i_wdata; 38 | end 39 | end 40 | 41 | always@* begin 42 | rdata = {mem[rptr-1], mem[rptr], mem[rptr+1]}; 43 | end 44 | 45 | // output register 46 | always@(posedge i_clk) begin 47 | o_rdata <= rdata; 48 | end 49 | 50 | // Write Pointer 51 | always@(posedge i_clk) begin 52 | if(!i_rstn) begin 53 | wptr <= 0; 54 | end 55 | else begin 56 | if(i_wr) begin 57 | wptr <= (wptr == LINE_LENGTH-1) ? 0 : wptr+1; 58 | end 59 | end 60 | end 61 | 62 | // Read Pointer 63 | always@(posedge i_clk) begin 64 | if(!i_rstn) begin 65 | rptr <= 0; 66 | end 67 | else begin 68 | if(i_rd) begin 69 | rptr <= (rptr == LINE_LENGTH-1) ? 0 : rptr+1; 70 | end 71 | end 72 | end 73 | 74 | endmodule 75 | 76 | /* 77 | INSTANTIATION TEMPLATE 78 | ps_linebuffer 79 | #(.LINE_LENGTH(640)) 80 | LINEBUF0_i ( 81 | .i_clk (), 82 | .i_rstn (), // sync active low reset 83 | .i_wr (), // write enable 84 | .i_wdata (), // 8-bit write data 85 | .i_rd (), // read enable 86 | .o_rdata () // 72-bit read data 87 | ); 88 | */ -------------------------------------------------------------------------------- /rtl/ps_sobel.v: -------------------------------------------------------------------------------- 1 | module ps_sobel 2 | ( 3 | input wire i_clk, // input clock 4 | input wire i_rstn, // sync active-low reset 5 | 6 | // kernel control interface 7 | input wire [23:0] i_r0_data, // three greyscale pixels from each row 8 | input wire [23:0] i_r1_data, 9 | input wire [23:0] i_r2_data, 10 | input wire i_valid, 11 | 12 | input wire [25:0] i_threshold, 13 | 14 | // output interface 15 | output reg [7:0] o_data, // 8-bit result 16 | output reg o_valid // valid flag 17 | ); 18 | 19 | integer i; 20 | 21 | // 3x3 kernel 22 | reg [7:0] kernelX [8:0]; 23 | reg [7:0] kernelY [8:0]; 24 | 25 | // stage 1: multiply 26 | wire [71:0] rowdata; 27 | reg [15:0] stage1_dataX_reg [8:0]; 28 | reg [15:0] stage1_dataY_reg [8:0]; 29 | reg stage1_valid; 30 | 31 | 32 | reg [15:0] stage1_dataX [8:0]; 33 | reg [15:0] stage1_dataY [8:0]; 34 | reg stage1_reg_valid; 35 | 36 | 37 | // stage 2: accumulate 38 | reg [15:0] stage2_accumulatorX, stage2_accumulatorY; 39 | reg [15:0] stage2_dataX, stage2_dataY; 40 | reg stage2_valid; 41 | 42 | // stage 3: convolve 43 | reg [25:0] stage3_dataX_reg, stage3_dataY_reg; 44 | wire [25:0] stage3_data; 45 | reg stage3_valid; 46 | 47 | 48 | // KERNEL DEFINITION: 3X3 GAUSSIAN BLUR 49 | initial begin 50 | kernelX[0] = 1; 51 | kernelX[1] = 0; 52 | kernelX[2] = -1; 53 | kernelX[3] = 2; 54 | kernelX[4] = 0; 55 | kernelX[5] = -2; 56 | kernelX[6] = 1; 57 | kernelX[7] = 0; 58 | kernelX[8] = -1; 59 | 60 | kernelY[0] = 1; 61 | kernelY[1] = 2; 62 | kernelY[2] = 1; 63 | kernelY[3] = 0; 64 | kernelY[4] = 0; 65 | kernelY[5] = 0; 66 | kernelY[6] = -1; 67 | kernelY[7] = -2; 68 | kernelY[8] = -1; 69 | end 70 | 71 | // PIPELINE STAGE 1 (2 cycles) 72 | // 73 | assign rowdata = {i_r0_data, i_r1_data, i_r2_data}; 74 | 75 | // multiply pixel data by kernel 76 | always@(posedge i_clk) begin 77 | if(!i_rstn) begin 78 | stage1_valid <= 0; 79 | for(i=0; i<9; i=i+1) begin 80 | stage1_dataX_reg[i] <= 0; 81 | end 82 | for(i=0; i<9; i=i+1) begin 83 | stage1_dataY_reg[i] <= 0; 84 | end 85 | end 86 | else begin 87 | stage1_valid <= i_valid; 88 | for(i=0; i<9; i=i+1) begin 89 | stage1_dataX_reg[i] <= $signed(kernelX[i]) * 90 | $signed({1'b0, rowdata[i*8+:8]}); 91 | end 92 | for(i=0; i<9; i=i+1) begin 93 | stage1_dataY_reg[i] <= $signed(kernelY[i]) * 94 | $signed({1'b0, rowdata[i*8+:8]}); 95 | end 96 | end 97 | end 98 | 99 | // another register here for performance 100 | always@(posedge i_clk) begin 101 | if(!i_rstn) begin 102 | stage1_reg_valid <= 0; 103 | for(i=0; i<9; i=i+1) begin 104 | stage1_dataX[i] <= 0; 105 | stage1_dataY[i] <= 0; 106 | end 107 | end 108 | else begin 109 | stage1_reg_valid <= stage1_valid; 110 | for(i=0; i<9; i=i+1) begin 111 | stage1_dataX[i] <= stage1_dataX_reg[i]; 112 | end 113 | for(i=0; i<9; i=i+1) begin 114 | stage1_dataY[i] <= stage1_dataY_reg[i]; 115 | end 116 | end 117 | end 118 | 119 | // PIPELINE STAGE 2 (1 cycle) 120 | // 121 | // sum all the stage 1 data 122 | always@* begin 123 | stage2_accumulatorX = 0; 124 | stage2_accumulatorY = 0; 125 | 126 | for(i=0; i<9; i=i+1) begin 127 | stage2_accumulatorX = $signed(stage2_accumulatorX) + 128 | $signed(stage1_dataX[i]); 129 | end 130 | for(i=0; i<9; i=i+1) begin 131 | stage2_accumulatorY = $signed(stage2_accumulatorY) + 132 | $signed(stage1_dataY[i]); 133 | end 134 | end 135 | 136 | // and register it 137 | always@(posedge i_clk) begin 138 | if(!i_rstn) begin 139 | stage2_valid <= 0; 140 | stage2_dataX <= 0; 141 | stage2_dataY <= 0; 142 | end 143 | else begin 144 | stage2_valid <= stage1_reg_valid; 145 | stage2_dataX <= stage2_accumulatorX; 146 | stage2_dataY <= stage2_accumulatorY; 147 | end 148 | end 149 | 150 | // PIPELINE STAGE 3 (1 cycle) 151 | // 152 | // square X and Y kernel results 153 | always@(posedge i_clk) begin 154 | if(!i_rstn) begin 155 | stage3_dataX_reg <= 0; 156 | stage3_dataY_reg <= 0; 157 | stage3_valid <= 0; 158 | end 159 | else begin 160 | stage3_dataX_reg <= $signed(stage2_dataX) * $signed(stage2_dataX); 161 | stage3_dataY_reg <= $signed(stage2_dataY) * $signed(stage2_dataY); 162 | stage3_valid <= stage2_valid; 163 | end 164 | end 165 | 166 | // and sum them 167 | assign stage3_data = stage3_dataX_reg + stage3_dataY_reg; 168 | 169 | // PIPELINE STAGE 4 (1 cycle) 170 | // 171 | // threshold the summation instead of taking square root 172 | always@(posedge i_clk) begin 173 | if(!i_rstn) begin 174 | o_valid <= 0; 175 | o_data <= 0; 176 | end 177 | else begin 178 | o_valid <= stage3_valid; 179 | o_data <= (stage3_data > i_threshold) ? 8'hFF:8'h0; 180 | end 181 | end 182 | 183 | 184 | endmodule -------------------------------------------------------------------------------- /rtl/ps_sobel_top.v: -------------------------------------------------------------------------------- 1 | // module: ps_sobel_top 2 | // 3 | // Wraps ps_kernel_control and ps_sobel. 4 | // 5 | // Contains passthrough logic for when filter is disabled. 6 | // 7 | module ps_sobel_top 8 | ( 9 | input wire i_clk, // input clock 10 | input wire i_rstn, // active low sync reset 11 | input wire i_enable, // filter enable 12 | input wire i_flush, 13 | 14 | input wire [23:0] i_threshold, 15 | 16 | input wire [11:0] i_data, 17 | input wire i_almostempty, 18 | output reg o_rd, 19 | 20 | input wire i_obuf_rd, 21 | output wire [11:0] o_obuf_data, 22 | output wire [4:0] o_obuf_fill, 23 | output wire o_obuf_full, 24 | output wire o_obuf_almostfull, 25 | output wire o_obuf_empty, 26 | output wire o_obuf_almostempty 27 | ); 28 | 29 | wire [23:0] r0_data, r1_data, r2_data; 30 | wire valid; 31 | wire req; 32 | wire [7:0] sobel_dout; 33 | wire sobel_valid; 34 | 35 | reg nxt_rd; 36 | reg nxt_din_valid, din_valid; 37 | reg [9:0] nxt_rdCounter, rdCounter; 38 | 39 | reg [11:0] obuf_wdata; 40 | reg obuf_wr; 41 | 42 | reg STATE, NEXT_STATE; 43 | localparam STATE_IDLE = 0, 44 | STATE_ACTIVE = 1; 45 | 46 | 47 | // FSM next state logic for FIFO reads 48 | // 49 | always@* begin 50 | nxt_rd = 0; 51 | nxt_din_valid = 0; 52 | NEXT_STATE = STATE; 53 | 54 | case(STATE) 55 | 56 | STATE_IDLE: begin 57 | case(i_enable) 58 | 0: begin 59 | if(!i_almostempty) begin 60 | nxt_rd = 1; 61 | nxt_din_valid = 1; 62 | NEXT_STATE = STATE_ACTIVE; 63 | end 64 | end 65 | 66 | 1: begin 67 | if(!i_almostempty && req) begin 68 | nxt_rd = 1; 69 | nxt_din_valid = 1; 70 | NEXT_STATE = STATE_ACTIVE; 71 | end 72 | end 73 | endcase 74 | end 75 | 76 | STATE_ACTIVE: begin 77 | case(i_enable) 78 | 0: begin 79 | nxt_rd = (!i_almostempty); 80 | nxt_din_valid = (!i_almostempty); 81 | NEXT_STATE = (i_almostempty) ? STATE_IDLE : STATE_ACTIVE; 82 | end 83 | 84 | 1: begin 85 | nxt_rd = (!i_almostempty && req); 86 | nxt_din_valid = (!i_almostempty && req); 87 | NEXT_STATE = (i_almostempty || !req) ? STATE_IDLE : STATE_ACTIVE; 88 | end 89 | endcase 90 | end 91 | 92 | endcase 93 | end 94 | 95 | // FSM sync process 96 | // 97 | always@(posedge i_clk) begin 98 | if(!i_rstn) begin 99 | o_rd <= 0; 100 | din_valid <= 0; 101 | rdCounter <= 0; 102 | STATE <= STATE_IDLE; 103 | end 104 | else begin 105 | o_rd <= nxt_rd; 106 | din_valid <= nxt_din_valid; 107 | rdCounter <= nxt_rdCounter; 108 | STATE <= NEXT_STATE; 109 | end 110 | end 111 | 112 | // passthrough logic 113 | always@* begin 114 | if(i_enable) begin 115 | obuf_wdata = {sobel_dout, 4'b0}; 116 | obuf_wr = sobel_valid; 117 | end 118 | else begin 119 | obuf_wdata = i_data; 120 | obuf_wr = din_valid; 121 | end 122 | end 123 | 124 | ps_kernel_control 125 | #(.LINE_LENGTH(640), 126 | .LINE_COUNT (480), 127 | .DATA_WIDTH (8)) 128 | sobel_ctrl_i ( 129 | .i_clk (i_clk ), 130 | .i_rstn (i_rstn&&(~i_flush) ), 131 | 132 | .i_data (i_data[11:4] ), 133 | .i_valid (din_valid ), 134 | .o_req (req ), 135 | 136 | .o_r0_data (r0_data ), 137 | .o_r1_data (r1_data ), 138 | .o_r2_data (r2_data ), 139 | .o_valid (valid ) 140 | ); 141 | 142 | ps_sobel 143 | sobel_i ( 144 | .i_clk (i_clk ), 145 | .i_rstn (i_rstn&&(~i_flush) ), 146 | .i_threshold (i_threshold ), 147 | 148 | .i_r0_data (r0_data ), 149 | .i_r1_data (r1_data ), 150 | .i_r2_data (r2_data ), 151 | .i_valid (valid ), 152 | 153 | .o_data (sobel_dout ), 154 | .o_valid (sobel_valid ) 155 | ); 156 | 157 | fifo_sync 158 | #(.DATA_WIDTH (12), 159 | .ADDR_WIDTH (10), 160 | .ALMOSTFULL_OFFSET (2), 161 | .ALMOSTEMPTY_OFFSET(1)) 162 | ps_obuf_i ( 163 | .i_clk (i_clk), 164 | .i_rstn (i_rstn&&(~i_flush) ), 165 | 166 | .i_wr (obuf_wr), 167 | .i_data (obuf_wdata), 168 | 169 | .i_rd (i_obuf_rd), 170 | .o_data (o_obuf_data), 171 | 172 | .o_fill (o_obuf_fill), 173 | 174 | .o_full (o_obuf_full), 175 | .o_almostfull (o_obuf_almostfull), 176 | .o_empty (o_obuf_empty), 177 | .o_almostempty (o_obuf_almostempty) 178 | ); 179 | endmodule -------------------------------------------------------------------------------- /rtl/sys_control.v: -------------------------------------------------------------------------------- 1 | // sys_control.v 2 | // 3 | // This module acts as an interface between board inputs and 4 | // pipeline control. 5 | // 6 | // 7 | `default_nettype none 8 | // 9 | `define MODE_PASSTHROUGH 0 10 | // 11 | module sys_control 12 | ( 13 | input wire i_sysclk, 14 | input wire i_rstn, 15 | 16 | input wire i_sof, 17 | 18 | input wire i_btn_mode, 19 | input wire i_sw_gaussian, 20 | input wire i_sw_sobel, 21 | 22 | input wire i_btn_incSobel, 23 | input wire i_btn_decSobel, 24 | 25 | output reg o_cfg_start, 26 | output reg o_mode, 27 | output reg o_pipe_flush, 28 | 29 | output reg o_gaussian_enable, 30 | output reg o_sobel_enable, 31 | output reg [25:0] o_sobel_threshold, 32 | output reg o_thresholdBounds 33 | ); 34 | 35 | // ============================================================= 36 | // Parameters, Registers, and Wires 37 | // ============================================================= 38 | localparam THRESHOLD_WIDTH = 26; 39 | localparam THRESHOLD_STEPSIZE = 500; 40 | 41 | reg STATE; 42 | localparam STATE_CFG = 0, 43 | STATE_ACTIVE = 1; 44 | 45 | wire db_btn_mode; 46 | reg btn1, btn2; 47 | wire db_btn_posedge; 48 | wire db_btn_incSobel, db_btn_decSobel; 49 | reg incSobel_q1, incSobel_q2; 50 | reg decSobel_q1, decSobel_q2; 51 | wire incSobel_posedge, decSobel_posedge; 52 | 53 | reg FLUSH_STATE; 54 | localparam FLUSH_IDLE = 0, 55 | FLUSH_ACTIVE = 1; 56 | 57 | reg sw_gaussian_q1, sw_gaussian_q2; 58 | wire delta_sw_gaussian; 59 | 60 | reg sw_sobel_q1, sw_sobel_q2; 61 | wire delta_sw_sobel; 62 | 63 | debounce 64 | #(.DB_COUNT(500_000)) // 20ms debounce period 65 | db_mode_i ( 66 | .i_clk (i_sysclk ), 67 | .i_input (i_btn_mode ), 68 | .o_db (db_btn_mode ) 69 | ); 70 | 71 | debounce 72 | #(.DB_COUNT(500_000)) // 20ms debounce period 73 | db_incSobel_i ( 74 | .i_clk (i_sysclk ), 75 | .i_input (i_btn_incSobel ), 76 | .o_db (db_btn_incSobel ) 77 | ); 78 | 79 | debounce 80 | #(.DB_COUNT(500_000)) // 20ms debounce period 81 | db_dcSobel_i ( 82 | .i_clk (i_sysclk ), 83 | .i_input (i_btn_decSobel ), 84 | .o_db (db_btn_decSobel ) 85 | ); 86 | 87 | // ============================================================= 88 | // Implementation: 89 | // ============================================================= 90 | 91 | // 92 | // Configure camera to ROM values on startup or reset 93 | // 94 | always@(posedge i_sysclk) begin 95 | if(!i_rstn) begin 96 | o_cfg_start <= 0; 97 | STATE <= 0; 98 | end 99 | else begin 100 | case(STATE) 101 | STATE_CFG: begin 102 | o_cfg_start <= 1; 103 | STATE <= 1; 104 | end 105 | 106 | STATE_ACTIVE: begin 107 | o_cfg_start <= 0; 108 | STATE <= 1; 109 | end 110 | endcase 111 | end 112 | end 113 | 114 | // 115 | // Toggle mode on button press 116 | // 117 | initial o_mode = 0; 118 | always@(posedge i_sysclk) begin 119 | if(!i_rstn) begin 120 | {btn1, btn2} <= 2'b0; 121 | end 122 | else begin 123 | {btn1, btn2} <= {db_btn_mode, btn1}; 124 | end 125 | end 126 | assign db_btn_posedge = ((btn1 == 1) && (btn2 == 0)); 127 | 128 | always@(posedge i_sysclk) begin 129 | if(!i_rstn) begin 130 | o_mode <= `MODE_PASSTHROUGH; 131 | end 132 | else begin 133 | if(db_btn_posedge) o_mode <= ~o_mode; 134 | end 135 | end 136 | 137 | // 138 | // Filter enables 139 | // 140 | always@(posedge i_sysclk) begin 141 | if(o_mode == `MODE_PASSTHROUGH) 142 | o_gaussian_enable <= 0; 143 | else begin 144 | o_gaussian_enable <= (i_sw_gaussian); 145 | end 146 | end 147 | always@(posedge i_sysclk) begin 148 | if(o_mode == `MODE_PASSTHROUGH) 149 | o_sobel_enable <= 0; 150 | else begin 151 | o_sobel_enable <= (i_sw_sobel); 152 | end 153 | end 154 | 155 | // Enable edge detectors 156 | // 157 | always@(posedge i_sysclk) begin 158 | if(!i_rstn) begin 159 | {sw_gaussian_q1, sw_gaussian_q2} <= 2'b0; 160 | end 161 | else begin 162 | {sw_gaussian_q1, sw_gaussian_q2} <= {i_sw_gaussian, sw_gaussian_q1}; 163 | end 164 | end 165 | assign delta_sw_gaussian = (sw_gaussian_q1 != sw_gaussian_q2); 166 | 167 | always@(posedge i_sysclk) begin 168 | if(!i_rstn) begin 169 | {sw_sobel_q1, sw_sobel_q2} <= 2'b0; 170 | end 171 | else begin 172 | {sw_sobel_q1, sw_sobel_q2} <= {i_sw_sobel, sw_sobel_q1}; 173 | end 174 | end 175 | assign delta_sw_sobel = (sw_sobel_q1 != sw_sobel_q2); 176 | 177 | // 178 | // Flush the pipeline if a filter is applied 179 | // -> hold the flush until start of frame 180 | // 181 | always@(posedge i_sysclk) begin 182 | if(!i_rstn) begin 183 | o_pipe_flush <= 0; 184 | FLUSH_STATE <= FLUSH_IDLE; 185 | end 186 | else begin 187 | if(o_mode != `MODE_PASSTHROUGH ) begin 188 | case(FLUSH_STATE) 189 | FLUSH_IDLE: begin 190 | o_pipe_flush <= 0; 191 | FLUSH_STATE <= (delta_sw_gaussian||delta_sw_sobel) ? FLUSH_ACTIVE:FLUSH_IDLE; 192 | end 193 | 194 | FLUSH_ACTIVE: begin 195 | o_pipe_flush <= 1; 196 | FLUSH_STATE <= (i_sof) ? FLUSH_IDLE:FLUSH_ACTIVE; 197 | end 198 | endcase 199 | end 200 | else o_pipe_flush <= 0; 201 | end 202 | end 203 | 204 | // Sobel Thresholding Control 205 | // 206 | 207 | // Enable edge detectors 208 | // 209 | always@(posedge i_sysclk) begin 210 | if(!i_rstn) begin 211 | {incSobel_q1, incSobel_q2} <= 2'b0; 212 | end 213 | else begin 214 | {incSobel_q1, incSobel_q2} <= {db_btn_incSobel, incSobel_q1}; 215 | end 216 | end 217 | assign incSobel_posedge = (incSobel_q1==1)&&(incSobel_q2==0); 218 | 219 | always@(posedge i_sysclk) begin 220 | if(!i_rstn) begin 221 | {decSobel_q1, decSobel_q2} <= 2'b0; 222 | end 223 | else begin 224 | {decSobel_q1, decSobel_q2} <= {db_btn_decSobel, decSobel_q1}; 225 | end 226 | end 227 | assign decSobel_posedge = (decSobel_q1==1)&&(decSobel_q2==0); 228 | 229 | 230 | always@(posedge i_sysclk) begin 231 | if(!i_rstn) begin 232 | o_sobel_threshold <= 10; 233 | end 234 | else begin 235 | if(incSobel_posedge) begin 236 | if(o_sobel_threshold < 100) begin 237 | o_sobel_threshold <= o_sobel_threshold+1; 238 | o_thresholdBounds <= 0; 239 | end 240 | else begin 241 | o_sobel_threshold <= o_sobel_threshold; 242 | o_thresholdBounds <= 1; 243 | end 244 | end 245 | else if(decSobel_posedge) begin 246 | if(o_sobel_threshold > 0) begin 247 | o_sobel_threshold <= o_sobel_threshold-1; 248 | o_thresholdBounds <= 0; 249 | end 250 | else begin 251 | o_sobel_threshold <= o_sobel_threshold; 252 | o_thresholdBounds <= 1; 253 | end 254 | end 255 | end 256 | end 257 | 258 | endmodule -------------------------------------------------------------------------------- /rtl/sys_top.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | // 3 | module sys_top 4 | ( 5 | input wire i_sysclk, // 125 MHz board clock 6 | input wire i_rst, // active-high board button 7 | 8 | // camera interface 9 | output wire o_cam_xclk, // 24MHz clock to camera from DCM 10 | output wire o_cam_rstn, // camera active low reset 11 | output wire o_cam_pwdn, // camera active high power down 12 | 13 | input wire i_cam_pclk, // camera generated pixel clock 14 | input wire i_cam_vsync, // camera vsync 15 | input wire i_cam_href, // camera href 16 | input wire [7:0] i_cam_data, // camera 8-bit data in 17 | 18 | // i2c interface 19 | inout wire SCL, // bidirectional SCL 20 | inout wire SDA, // bidirectional SDA 21 | 22 | // HDMI interface 23 | output wire [3:0] o_TMDS_P, 24 | output wire [3:0] o_TMDS_N, 25 | 26 | // controls 27 | input wire btn_mode, 28 | input wire btn_decSobel, 29 | input wire btn_incSobel, 30 | 31 | input wire sw_gaussian, 32 | input wire sw_sobel, 33 | input wire sw_freeze, 34 | 35 | // status 36 | output wire led_mode, 37 | output wire led_gaussian, 38 | output wire led_sobel, 39 | output wire led_threshold 40 | ); 41 | 42 | 43 | // ============================================================= 44 | // Parameters, Registers, and Wires 45 | // ============================================================= 46 | // DCM 47 | wire clk_25MHz; 48 | wire clk_250MHz; 49 | wire clk_PS; 50 | 51 | // Debounce 52 | wire db_rstn; 53 | 54 | // System Control 55 | wire cfg_start; 56 | wire sys_mode; 57 | wire gaussian_enable; 58 | wire sobel_enable; 59 | wire pipe_flush; 60 | wire [25:0] sobel_threshold; 61 | wire thresholdBounds; 62 | 63 | // Camera Block 64 | wire i_scl, i_sda; 65 | wire o_scl, o_sda; 66 | wire sof; 67 | wire cam_obuf_rd; 68 | wire [11:0] cam_obuf_rdata; 69 | wire cam_obuf_almostempty; 70 | wire cfg_done; 71 | 72 | // Greyscale Block 73 | wire pp_obuf_rd; 74 | wire [11:0] pp_obuf_rdata; 75 | wire pp_obuf_almostempty; 76 | wire [10:0] pp_obuf_fill; 77 | 78 | // Gaussian Block 79 | wire gssn_obuf_rd; 80 | wire [11:0] gssn_obuf_rdata; 81 | wire gssn_obuf_almostempty; 82 | 83 | // Sobel Block 84 | wire sobel_obuf_rd; 85 | wire [11:0] sobel_obuf_rdata; 86 | wire sobel_obuf_almostempty; 87 | 88 | // Display Interface 89 | wire [18:0] framebuf_raddr; 90 | wire [11:0] framebuf_rdata; 91 | 92 | // ============================================================= 93 | // Implementation: 94 | // ============================================================= 95 | assign o_cam_rstn = 1'b1; // sw reset instead 96 | assign o_cam_pwdn = 1'b0; 97 | 98 | assign led_mode = sys_mode; 99 | assign led_gaussian = gaussian_enable; 100 | assign led_sobel = sobel_enable; 101 | assign led_threshold = thresholdBounds; 102 | 103 | // **** Debounce Reset button **** 104 | // -> debounced in camera pclk domain (24MHz) 105 | debounce 106 | //#(.DB_COUNT(476190)) // 20ms debounce period 107 | #(.DB_COUNT(1)) // 20ms debounce period 108 | db_inst ( 109 | .i_clk (i_cam_pclk ), 110 | .i_input (~i_rst ), 111 | .o_db (db_rstn ) // 24MHz clock domain debounced reset 112 | ); 113 | 114 | 115 | // **** Async Reset Synchronizers **** 116 | // 125 MHz 117 | reg sync_rstn_PS, q_rstn_PS; 118 | always@(posedge i_sysclk or negedge db_rstn) begin 119 | if(!db_rstn) {sync_rstn_PS, q_rstn_PS} <= 2'b0; 120 | else {sync_rstn_PS, q_rstn_PS} <= {q_rstn_PS, 1'b1}; 121 | end 122 | 123 | // 25 MHz 124 | reg sync_rstn_25, q_rstn_25; 125 | always@(posedge clk_25MHz or negedge db_rstn) begin 126 | if(!db_rstn) {sync_rstn_25, q_rstn_25} <= 2'b0; 127 | else {sync_rstn_25, q_rstn_25} <= {q_rstn_25, 1'b1}; 128 | end 129 | 130 | 131 | // ============================================================= 132 | // Submodule Instantiation: 133 | // ============================================================= 134 | //--------------------------------------------------- 135 | // Clocking Wizard: 136 | //--------------------------------------------------- 137 | clk_wiz_0 138 | dcm_i ( 139 | .clk_in1 (i_sysclk ), // 125MHz board clock 140 | .reset (1'b0 ), 141 | .clk_24MHz (o_cam_xclk ), // camera reference clock output 142 | .clk_25MHz (clk_25MHz ), // display pixel clock 143 | .clk_250MHz (clk_250MHz ), // display TMDS clock 144 | .clk_PS (clk_PS ) // processing system clock 145 | ); 146 | 147 | //--------------------------------------------------- 148 | // System Control: 149 | //--------------------------------------------------- 150 | sys_control 151 | ctrl_i ( 152 | .i_sysclk (i_sysclk ), // 125MHz clock 153 | .i_rstn (sync_rstn_PS ), // active-low sync reset 154 | 155 | .i_sof (sof ), 156 | 157 | .i_btn_mode (btn_mode ), // board button 158 | .i_sw_gaussian (sw_gaussian ), 159 | .i_sw_sobel (sw_sobel ), 160 | .i_btn_incSobel (btn_incSobel ), 161 | .i_btn_decSobel (btn_decSobel ), 162 | 163 | .o_cfg_start (cfg_start ), // config module start 164 | .o_gaussian_enable (gaussian_enable ), 165 | .o_sobel_enable (sobel_enable ), 166 | .o_mode (sys_mode ), 167 | .o_pipe_flush (pipe_flush ), 168 | .o_sobel_threshold (sobel_threshold ), 169 | .o_thresholdBounds (thresholdBounds ) 170 | ); 171 | 172 | //--------------------------------------------------- 173 | // Camera Block: 174 | //--------------------------------------------------- 175 | assign SCL = (o_scl) ? 1'bz : 1'b0; 176 | assign SDA = (o_sda) ? 1'bz : 1'b0; 177 | assign i_scl = SCL; 178 | assign i_sda = SDA; 179 | 180 | cam_top 181 | #(.T_CFG_CLK(8)) 182 | cam_i ( 183 | .i_cfg_clk (i_sysclk ), 184 | .i_rstn (sync_rstn_PS ), 185 | .o_sof (sof ), 186 | 187 | // OV7670 external inputs 188 | .i_cam_pclk (i_cam_pclk ), 189 | .i_cam_vsync (i_cam_vsync ), 190 | .i_cam_href (i_cam_href ), 191 | .i_cam_data (i_cam_data ), 192 | 193 | // i2c bidirectional pins 194 | .i_scl (i_scl ), 195 | .i_sda (i_sda ), 196 | .o_scl (o_scl ), 197 | .o_sda (o_sda ), 198 | 199 | // Controls 200 | .i_cfg_init (cfg_start ), 201 | .o_cfg_done (cfg_done ), 202 | 203 | // output buffer read interface 204 | .i_obuf_rclk (i_sysclk ), 205 | .i_obuf_rstn (sync_rstn_PS ), 206 | .i_obuf_rd (cam_obuf_rd ), 207 | .o_obuf_data (cam_obuf_rdata ), 208 | .o_obuf_empty (), 209 | .o_obuf_almostempty (cam_obuf_almostempty ), 210 | .o_obuf_fill () 211 | 212 | ); 213 | 214 | //--------------------------------------------------- 215 | // Greyscale Converter: 216 | //--------------------------------------------------- 217 | pp_preprocess pp_i ( 218 | .i_clk (i_sysclk ), 219 | .i_rstn (sync_rstn_PS ), 220 | .i_flush (pipe_flush||sw_freeze), 221 | 222 | // greyscale algorithm enable 223 | .i_mode (sys_mode ), 224 | 225 | // input interface 226 | .o_rd (cam_obuf_rd ), 227 | .i_data (cam_obuf_rdata ), 228 | .i_almostempty (cam_obuf_almostempty ), 229 | 230 | // output buffer interface 231 | .i_rd (pp_obuf_rd ), 232 | .o_data (pp_obuf_rdata ), 233 | .o_fill (), 234 | .o_almostempty (pp_obuf_almostempty ) 235 | ); 236 | 237 | //--------------------------------------------------- 238 | // Gaussian Operator: 239 | //--------------------------------------------------- 240 | ps_gaussian_top gaussian_i ( 241 | .i_clk (i_sysclk), 242 | .i_rstn (sync_rstn_PS), 243 | .i_enable (gaussian_enable), 244 | .i_flush (pipe_flush||sw_freeze), 245 | 246 | .i_data (pp_obuf_rdata), 247 | .i_almostempty (pp_obuf_almostempty), 248 | .o_rd (pp_obuf_rd), 249 | 250 | .i_obuf_rd (gssn_obuf_rd), 251 | .o_obuf_data (gssn_obuf_rdata), 252 | .o_obuf_fill (), 253 | .o_obuf_full (), 254 | .o_obuf_almostfull (), 255 | .o_obuf_empty (), 256 | .o_obuf_almostempty (gssn_obuf_almostempty) 257 | ); 258 | 259 | //--------------------------------------------------- 260 | // Sobel Operator: 261 | //--------------------------------------------------- 262 | ps_sobel_top sobel_i ( 263 | .i_clk (i_sysclk), 264 | .i_rstn (sync_rstn_PS), 265 | .i_enable (sobel_enable), 266 | .i_flush (pipe_flush||sw_freeze), 267 | .i_threshold (sobel_threshold), 268 | 269 | .i_data (gssn_obuf_rdata), 270 | .i_almostempty (gssn_obuf_almostempty), 271 | .o_rd (gssn_obuf_rd), 272 | 273 | .i_obuf_rd (sobel_obuf_rd), 274 | .o_obuf_data (sobel_obuf_rdata), 275 | .o_obuf_fill (), 276 | .o_obuf_full (), 277 | .o_obuf_almostfull (), 278 | .o_obuf_empty (), 279 | .o_obuf_almostempty (sobel_obuf_almostempty) 280 | ); 281 | 282 | 283 | //--------------------------------------------------- 284 | // Memory Interface: 285 | //--------------------------------------------------- 286 | mem_interface 287 | #(.DATA_WIDTH (12), 288 | .BRAM_DEPTH (307200) 289 | ) 290 | mem_i( 291 | .i_clk (i_sysclk ), // 125 MHz board clock 292 | .i_rstn (sync_rstn_PS ), // active-low sync reset 293 | .i_flush (pipe_flush||sw_freeze ), 294 | 295 | // Input FIFO read interface 296 | .o_rd (sobel_obuf_rd ), 297 | .i_rdata (sobel_obuf_rdata ), 298 | .i_almostempty (sobel_obuf_almostempty ), 299 | 300 | 301 | // frame buffer read interface 302 | .i_rclk (clk_25MHz ), 303 | .i_raddr (framebuf_raddr ), 304 | .o_rdata (framebuf_rdata ) 305 | ); 306 | 307 | 308 | //--------------------------------------------------- 309 | // Display Interface: 310 | //--------------------------------------------------- 311 | display_interface 312 | display_i( 313 | .i_p_clk (clk_25MHz ), // 25 MHz display clock 314 | .i_tmds_clk (clk_250MHz ), // 250 MHz TMDS clock 315 | .i_rstn (db_rstn ), 316 | .i_mode (sys_mode ), // mode; color or greyscale 317 | 318 | // frame buffer read interface 319 | .o_raddr (framebuf_raddr ), 320 | .i_rdata (framebuf_rdata ), 321 | 322 | // TMDS out 323 | .o_TMDS_P (o_TMDS_P ), // HDMI outputs 324 | .o_TMDS_N (o_TMDS_N ) 325 | ); 326 | 327 | endmodule -------------------------------------------------------------------------------- /rtl/vtc.v: -------------------------------------------------------------------------------- 1 | // Video Timing Control (VTC) module 2 | // this module generates hsync and vsync signals for 640x480 resolution 3 | // 4 | // timings are parameterized but make sure pixel clock is correct! 5 | // 6 | 7 | module vtc 8 | #( 9 | // total frame size 10 | parameter RES_WIDTH = 800, 11 | parameter RES_HEIGHT = 525, 12 | 13 | // active area 14 | parameter ACTIVE_X = 640, 15 | parameter ACTIVE_Y = 480, 16 | 17 | // hsync pulse width, back porch, front porch 18 | parameter HSYNC_WIDTH = 96, 19 | parameter HSYNC_BP = 48, 20 | parameter HSYNC_FP = 16, 21 | 22 | // vsync pulse width, back porch, front porch 23 | parameter VSYNC_WIDTH = 2, 24 | parameter VSYNC_BP = 33, 25 | parameter VSYNC_FP = 10, 26 | 27 | parameter COUNTER_WIDTH = 10 28 | ) 29 | ( 30 | input wire i_clk, // pixel clock 31 | input wire i_rstn, // synchronous active low reset 32 | 33 | // display timing 34 | output wire o_vsync, 35 | output wire o_hsync, 36 | output wire o_active, 37 | 38 | // counter passthrough 39 | output wire [COUNTER_WIDTH-1:0] o_counterX, 40 | output wire [COUNTER_WIDTH-1:0] o_counterY 41 | ); 42 | 43 | 44 | 45 | // horizontal and vertical counters 46 | //localparam COUNTER_X_WIDTH = $clog2(RES_WIDTH); 47 | //localparam COUNTER_Y_WIDTH = $clog2(RES_HEIGHT); 48 | reg [COUNTER_WIDTH-1:0] counterX; 49 | reg [COUNTER_WIDTH-1:0] counterY; 50 | 51 | 52 | initial begin 53 | counterX = 0; 54 | counterY = 0; 55 | end 56 | 57 | // 58 | // vsync and hsync counters 59 | // 60 | always@(posedge i_clk) begin 61 | if(!i_rstn) begin 62 | counterX <= 0; 63 | end 64 | else begin 65 | counterX <= (counterX == 799) ? 0 : (counterX + 1); 66 | end 67 | end 68 | 69 | always@(posedge i_clk) begin 70 | if(!i_rstn) begin 71 | counterY <= 0; 72 | end 73 | else begin 74 | if(counterX == 799) begin 75 | counterY <= (counterY == 524) ? 0 : (counterY + 1); 76 | end 77 | end 78 | end 79 | 80 | // 81 | // output combinatorial logic 82 | // 83 | /* 84 | always@(posedge i_clk) begin 85 | if(!i_rstn) begin 86 | o_active <= 0; 87 | o_hsync <= 0; 88 | o_vsync <= 0; 89 | end 90 | else begin 91 | o_active <= (counterX < 640) && (counterY < 480); 92 | o_hsync <= (counterX >= 656) && (counterX < 752); 93 | o_vsync <= (counterY >= 490) && (counterY < 492); 94 | end 95 | end 96 | */ 97 | assign o_hsync = ((counterX >= ACTIVE_X + HSYNC_FP) && 98 | (counterX < ACTIVE_X + HSYNC_FP + HSYNC_WIDTH)); 99 | 100 | assign o_vsync = ((counterY >= ACTIVE_Y + VSYNC_FP) && 101 | (counterY < ACTIVE_Y + VSYNC_FP + VSYNC_WIDTH)); 102 | 103 | assign o_active = ((counterX >= 0) && (counterX < ACTIVE_X) && 104 | (counterY >= 0) && (counterY < ACTIVE_Y)); 105 | 106 | assign o_counterX = counterX; 107 | assign o_counterY = counterY; 108 | 109 | endmodule // vtc -------------------------------------------------------------------------------- /tb/camera_config_tb.v: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // 4 | module camera_config_tb (); 5 | 6 | 7 | reg clk = 0; 8 | reg rstn; 9 | 10 | wire i_scl, i_sda; 11 | wire o_scl, o_sda; 12 | wire SCL, SDA; 13 | 14 | pullup(SCL); 15 | pullup(SDA); 16 | assign SCL = (o_scl) ? 1'bz:1'b0; 17 | assign SDA = (o_sda) ? 1'bz:1'b0; 18 | 19 | assign i_scl = SCL; 20 | assign i_sda = SDA; 21 | 22 | camera_config DUT( 23 | .i_clk (clk), 24 | .i_rstn (rstn), 25 | .i_scl (i_scl), 26 | .i_sda (i_sda), 27 | .o_scl (o_scl), 28 | .o_sda (o_sda) 29 | ); 30 | 31 | always#5 clk = ~clk; 32 | 33 | initial begin 34 | $dumpfile("camera_config_tb.vcd"); 35 | $dumpvars(0, camera_config_tb); 36 | end 37 | 38 | initial begin 39 | rstn = 0; 40 | #100; 41 | rstn = 1; 42 | 43 | #6_000_000; 44 | $finish; 45 | end 46 | 47 | endmodule -------------------------------------------------------------------------------- /tb/capture_tb.sv: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | module capture_tb(); 4 | 5 | 6 | // DUT I/O 7 | // 8 | logic clk = 0; 9 | logic rstn; 10 | logic vsync; 11 | logic href; 12 | logic [7:0] data; 13 | 14 | logic full = 0; 15 | 16 | logic o_wr; 17 | logic [11:0] o_wdata; 18 | 19 | logic [11:0] test_data; 20 | 21 | // DUT Instantiation 22 | // 23 | capture DUT( 24 | .i_clk (clk), 25 | .i_rstn (rstn), 26 | 27 | .i_vsync (vsync), 28 | .i_href (href), 29 | .i_data (data), 30 | 31 | .o_wr (o_wr), 32 | .o_wdata (o_wdata), 33 | .i_full (full), 34 | 35 | .o_sof () 36 | ); 37 | 38 | 39 | // Testbench Setup 40 | // 41 | localparam TESTRUNS = 5; 42 | localparam ROWCOUNT = 5; 43 | localparam ROWLENGTH = 10; 44 | 45 | logic [11:0] test_queue[$]; 46 | logic [11:0] test_expected; 47 | 48 | always#(21) clk = ~clk; 49 | 50 | task startFrame; 51 | begin 52 | vsync = 0; 53 | @(posedge clk); 54 | vsync = 1; 55 | repeat(3) @(posedge clk); // mimic vsync pulse 56 | vsync = 0; 57 | repeat(17) @(posedge clk); // mimic vsync back porch 58 | end 59 | endtask 60 | 61 | // Testbench 62 | // 63 | initial begin 64 | rstn = 0; 65 | vsync = 0; 66 | href = 0; 67 | data = 0; 68 | #100; 69 | 70 | rstn = 1; 71 | 72 | @(posedge clk) vsync = 1; 73 | repeat(3) @(posedge clk); 74 | @(posedge clk) vsync = 0; 75 | 76 | repeat(17) @(posedge clk); 77 | 78 | // repeat for # of frames 79 | for(int i=0; i o_raddr == $past(o_raddr)+1; 58 | endproperty 59 | A_bram_rdLatency_chk: assert property(bram_rdLatency_chk) 60 | else $stop; 61 | 62 | // check that reads are always aligned 63 | property bram_rdAlign_chk; 64 | @(posedge i_p_clk) disable iff(!i_rstn) 65 | ($fell(DUT.active)) |-> (o_raddr % 640 == 0); 66 | endproperty 67 | A_bram_rdAlign_chk: assert property(bram_rdAlign_chk) 68 | else $stop; 69 | 70 | // check that reads always start from zero for each frame 71 | property bram_rdStartAddr_chk; 72 | @(posedge i_p_clk) disable iff(!i_rstn) 73 | (DUT.counterX==0 && DUT.counterY==0) |-> (i_rdata == 0); 74 | endproperty 75 | A_bram_rdStartAddr_chk: assert property(bram_rdStartAddr_chk) 76 | else $stop; 77 | 78 | endmodule -------------------------------------------------------------------------------- /tb/gtkwave/camera_config.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.109 (w)1999-2020 BSI 3 | [*] Tue Aug 24 21:32:54 2021 4 | [*] 5 | [dumpfile] "C:\Users\work\Documents\repos\Edge-Detection\tb\gtkwave\camera_config_tb.vcd" 6 | [savefile] "C:\Users\work\Documents\repos\Edge-Detection\tb\gtkwave\camera_config.gtkw" 7 | [timestart] 0 8 | [size] 1000 600 9 | [pos] -1 -1 10 | *-9.000000 705 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 11 | [treeopen] camera_config_tb. 12 | [treeopen] camera_config_tb.DUT. 13 | [sst_width] 192 14 | [signals_width] 166 15 | [sst_expanded] 1 16 | [sst_vpaned_height] 158 17 | @28 18 | camera_config_tb.clk 19 | camera_config_tb.rstn 20 | @200 21 | -i/o 22 | @28 23 | camera_config_tb.SCL 24 | camera_config_tb.SDA 25 | @200 26 | -config state 27 | @28 28 | camera_config_tb.DUT.STATE[1:0] 29 | camera_config_tb.DUT.NEXT_STATE[1:0] 30 | @200 31 | -controls 32 | @22 33 | camera_config_tb.DUT.rom_addr[7:0] 34 | @28 35 | camera_config_tb.DUT.wr 36 | @22 37 | camera_config_tb.DUT.reg_addr[7:0] 38 | camera_config_tb.DUT.wdata[7:0] 39 | @200 40 | -ROM 41 | @22 42 | camera_config_tb.DUT.config_rom_i.i_addr[7:0] 43 | camera_config_tb.DUT.config_rom_i.o_data[15:0] 44 | @200 45 | -i2c master 46 | @29 47 | camera_config_tb.DUT.i2c_master_i.o_busy 48 | [pattern_trace] 1 49 | [pattern_trace] 0 50 | -------------------------------------------------------------------------------- /tb/linebuffer_tb.sv: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | module linebuffer_tb(); 4 | 5 | logic clk = 0; 6 | logic rstn; 7 | 8 | logic wr; 9 | logic [7:0] wdata; 10 | 11 | logic rd; 12 | logic [23:0] rdata; 13 | 14 | ps_linebuffer 15 | #(.LINE_LENGTH(640)) 16 | DUT( 17 | .i_clk (clk), 18 | .i_rstn (rstn), 19 | 20 | .i_wr (wr), 21 | .i_wdata (wdata), 22 | 23 | .i_rd (rd), 24 | .o_rdata (rdata) 25 | ); 26 | 27 | // Testbench Setup 28 | // 29 | logic [7:0] test_data1, test_data2, test_data3; 30 | 31 | logic [7:0] test_queue[$]; 32 | logic [23:0] test_expected; 33 | integer i; 34 | 35 | always#(6) clk = ~clk; 36 | 37 | // 38 | always@(posedge clk) begin 39 | if(wr) begin 40 | test_queue.push_front(wdata); 41 | end 42 | end 43 | 44 | initial begin 45 | rstn = 0; 46 | wr = 0; 47 | wdata = 0; 48 | rd = 0; 49 | #100; 50 | @(posedge clk) rstn <= 1; 51 | 52 | // fill the linebuffer 53 | $display("Writing data to linebuffer."); 54 | for(i=0; i<640; i=i+1) begin 55 | @(posedge clk) begin 56 | wr <= 1; 57 | wdata <= $urandom; 58 | end 59 | end 60 | @(posedge clk) wr <= 0; 61 | 62 | // read back data 63 | $display("Reading data from linebuffer."); 64 | @(posedge clk) rd <= 1; 65 | for(i=0; i<640; i=i+1) begin 66 | @(posedge clk) begin 67 | rd <= (i<639); 68 | end 69 | @(negedge clk) begin 70 | 71 | // special case: first pixel in row 72 | if(i==0) begin 73 | test_data1 = test_queue.pop_back(); 74 | test_data2 = test_queue.pop_back(); 75 | test_data3 = test_queue.pop_back(); 76 | test_expected[15:0] = {test_data1, test_data2}; 77 | assert(rdata[15:0] == test_expected[15:0]) 78 | else begin 79 | $error("Output data mismatch: Expected data = %h, Actual data = %h", test_expected, rdata); 80 | $stop; 81 | end 82 | end 83 | 84 | // special case: second pixel in row 85 | else if(i==1) begin 86 | test_expected = {test_data1, test_data2, test_data3}; 87 | assert(rdata == test_expected) 88 | else begin 89 | $error("Output data mismatch: Expected data = %h, Actual data = %h", test_expected, rdata); 90 | $stop; 91 | end 92 | end 93 | 94 | // special case: last pixel in row 95 | else if(i==639) begin 96 | test_expected[23:8] = {test_data2, test_data3}; 97 | assert(rdata[23:8] == test_expected[23:8]) 98 | else begin 99 | $error("Output data mismatch: Expected data = %h, Actual data = %h", test_expected, rdata); 100 | $stop; 101 | end 102 | end 103 | 104 | // default 105 | else begin 106 | test_data1 = test_data2; 107 | test_data2 = test_data3; 108 | test_data3 = test_queue.pop_back(); 109 | test_expected = {test_data1, test_data2, test_data3}; 110 | assert(rdata == test_expected) 111 | else begin 112 | $error("Output data mismatch: Expected data = %h, Actual data = %h", test_expected, rdata); 113 | $stop; 114 | end 115 | end 116 | end 117 | end 118 | repeat(5) @(posedge clk); 119 | $display("Linebuffer read/write tests passed!"); 120 | $stop; 121 | end 122 | 123 | 124 | endmodule -------------------------------------------------------------------------------- /tb/mem_interface_tb.sv: -------------------------------------------------------------------------------- 1 | 2 | module mem_interface_tb (); 3 | 4 | logic i_clk, i_rstn; 5 | logic disp_clk; 6 | logic i_flush = 0; 7 | 8 | logic i_req; 9 | 10 | logic o_rd; 11 | logic [11:0] i_rdata; 12 | logic i_almostempty; 13 | 14 | logic [18:0] i_raddr; 15 | logic [11:0] o_rdata; 16 | 17 | mem_interface DUT 18 | ( 19 | .i_clk (i_clk), 20 | .i_rstn (i_rstn), 21 | .i_flush (i_flush), 22 | 23 | .i_req (i_req), 24 | 25 | .o_rd (o_rd), 26 | .i_rdata (i_rdata), 27 | .i_almostempty(i_almostempty), 28 | 29 | .i_rclk (disp_clk), 30 | .i_raddr (i_raddr), 31 | .o_rdata (o_rdata) 32 | ); 33 | 34 | integer i, j, k; 35 | logic [11:0] test_queue[$]; 36 | logic [11:0] test_expected; 37 | logic [18:0] test_counter; 38 | logic v_past1_almostfull; 39 | logic v_past2_almostfull; 40 | 41 | always#(8) i_clk = ~i_clk; 42 | always#(20) disp_clk = ~disp_clk; 43 | 44 | // 45 | // 46 | always@(posedge i_clk) begin 47 | if(o_rd) begin 48 | i_rdata <= $urandom; 49 | test_queue.push_front(i_rdata); 50 | end 51 | end 52 | 53 | initial begin 54 | disp_clk = 0; 55 | i_clk = 0; 56 | i_rstn = 0; 57 | i_almostempty = 1; 58 | i_rdata = 0; 59 | i_raddr = 0; 60 | #100; 61 | i_rstn = 1; 62 | #100; 63 | 64 | // write to entire frame buffer in 10-pixel bursts 65 | for(i=0; i<30720; i=i+1) begin 66 | @(posedge i_clk) i_almostempty <= 0; 67 | repeat(9) @(posedge i_clk); 68 | @(posedge i_clk) i_almostempty <= 1; 69 | end 70 | 71 | repeat(5) @(posedge disp_clk); 72 | 73 | 74 | // read back the frame buffer and check that data matches 75 | //@(posedge disp_clk) i_raddr <= i_raddr+1; 76 | for(i=0; i<307199; i=i+1) begin 77 | @(posedge disp_clk) begin 78 | i_raddr <= i_raddr + 1; 79 | end 80 | @(negedge disp_clk) begin 81 | test_expected = test_queue.pop_back(); 82 | assert(o_rdata == test_expected) 83 | else begin 84 | $error("Output data mismatch: Expected data = %h, Actual data = %h", test_expected, o_rdata); 85 | $stop; 86 | end 87 | end 88 | end 89 | 90 | repeat(5) @(posedge disp_clk); 91 | $display("Test passed!"); 92 | $finish; 93 | end 94 | 95 | // module never reads from empty input fifo 96 | property ibuf_rdEmpty_chk; 97 | @(posedge i_clk) disable iff(!i_rstn) 98 | (i_almostempty) |=> !o_rd; 99 | endproperty 100 | A_ibuf_rdEmpty_chk: assert property(ibuf_rdEmpty_chk); 101 | 102 | // every time there is a fifo read, there is a write to memory 103 | property mem_wr_chk; 104 | @(posedge i_clk) disable iff(!i_rstn) 105 | (o_rd) |-> DUT.mem_wr; 106 | endproperty 107 | A_mem_wr_chk: assert property(mem_wr_chk); 108 | 109 | // check that no write addresses are skipped 110 | logic [18:0] t_prev_waddr; 111 | always@(posedge i_clk) begin 112 | if(DUT.mem_wr) t_prev_waddr <= DUT.mem_waddr; 113 | if(i_rstn) begin 114 | if(DUT.mem_wr && (t_prev_waddr!=0) && (t_prev_waddr != 307199)) begin 115 | assert(DUT.mem_waddr == t_prev_waddr+1) 116 | else $error("Write address skipped!"); 117 | end 118 | end 119 | end 120 | 121 | // block ram write address should never exceed bounds 122 | property mem_wraddrBounds_chk; 123 | @(posedge i_clk) disable iff(!i_rstn) 124 | DUT.mem_waddr < 307200; 125 | endproperty 126 | A_mem_wraddrBounds_chk: assert property(mem_wraddrBounds_chk); 127 | 128 | endmodule -------------------------------------------------------------------------------- /tb/mountain_bmp.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgeyhere/FPGA-Video-Processing/cea80bafc0d6f4e5dbbade748fdbe276a026a60c/tb/mountain_bmp.bmp -------------------------------------------------------------------------------- /tb/pp_preprocess_tb.sv: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | module pp_preprocess_tb(); 4 | 5 | logic i_clk; 6 | logic i_rstn; 7 | logic i_flush; 8 | logic i_mode; 9 | 10 | logic o_rd; 11 | logic [11:0] i_data; 12 | logic i_almostempty; 13 | 14 | logic i_rd; 15 | logic [11:0] o_data; 16 | logic [10:0] o_fill; 17 | logic o_almostempty; 18 | logic o_valid; 19 | 20 | pp_preprocess DUT( 21 | .i_clk (i_clk), 22 | .i_rstn (i_rstn), 23 | .i_flush (i_flush), 24 | .i_mode (i_mode), 25 | 26 | .o_rd (o_rd), 27 | .i_data (i_data), 28 | .i_almostempty (i_almostempty), 29 | 30 | .i_rd (i_rd), 31 | .o_data (o_data), 32 | .o_fill (o_fill), 33 | .o_almostempty (o_almostempty), 34 | .o_valid (o_valid) 35 | ); 36 | 37 | integer i; 38 | logic [11:0] test_queue[$]; 39 | logic [11:0] test_expected; 40 | logic [11:0] test_input; 41 | 42 | always#(4) i_clk = ~i_clk; 43 | 44 | // mimic 250 total words available from input fifo in 5 word bursts 45 | task inputData; 46 | begin 47 | for(i=0; i<50; i=i+1) begin 48 | @(posedge i_clk) i_almostempty <= 0; 49 | repeat(4) @(posedge i_clk); 50 | @(posedge i_clk) i_almostempty <= 1; 51 | end 52 | end 53 | endtask 54 | 55 | logic [7:0] r,g,b; 56 | function bit [11:0] convertGrey; 57 | input [11:0] i_rgb; 58 | begin 59 | r = {i_rgb[11:8],4'b0}; 60 | g = {i_rgb[7:4], 4'b0}; 61 | b = {i_rgb[3:0], 4'b0}; 62 | 63 | convertGrey = {((r>>2) + (r>>5) + (r>>6) + 64 | (g>>1) + (g>>4) + (g>>5) + 65 | (b>>3)), 66 | 4'b0 }; 67 | end 68 | endfunction 69 | 70 | // whenever there is a fifo read, generate random data; store in a queue 71 | always@(posedge i_clk) begin 72 | if(o_rd) begin 73 | i_data <= $urandom; 74 | test_queue.push_front(i_data); 75 | end 76 | end 77 | 78 | initial begin 79 | i_clk = 0; 80 | i_rstn = 0; 81 | i_flush = 0; 82 | i_mode = 0; // initialize in passthrough mode 83 | i_data = $urandom; 84 | i_almostempty = 1; 85 | i_rd = 0; 86 | #100; 87 | i_rstn = 1; 88 | 89 | // test passthrough mode 90 | // -> input data in 5 pixel bursts 91 | //test_queue.push_front(i_data); // FIFO has first word fallthrough 92 | inputData(); 93 | repeat(5) @(posedge i_clk); 94 | 95 | // -> read the data from the output buffer, check that it matches 96 | @(posedge i_clk) i_rd <= 1; 97 | for(i=0; i<250; i=i+1) begin 98 | @(posedge i_clk) begin 99 | i_rd <= (i<249); 100 | end 101 | @(negedge i_clk) begin 102 | if(o_valid) begin 103 | test_expected = test_queue.pop_back(); 104 | assert(o_data == test_expected) 105 | else begin 106 | $display("Output data mismatch: \n Expected data = %h, Actual data = %h \n", 107 | test_expected, o_data); 108 | $stop; 109 | end 110 | end 111 | end 112 | end 113 | @(posedge i_clk) i_rd <= 0; 114 | assert(test_queue.size() == 0) 115 | else begin 116 | $display("Not all inputs read!"); 117 | $stop; 118 | end 119 | $display("Passthrough Mode Readback Test Passed."); 120 | repeat(5) @(posedge i_clk); 121 | 122 | // 123 | // test grayscale conversion mode 124 | // 125 | $display("Starting Greyscale Conversion Test"); 126 | @(posedge i_clk) i_mode <= 1; 127 | 128 | // -> input data in 5 pixel bursts 129 | inputData(); 130 | 131 | // -> read the data from the output buffer, check that it matches 132 | @(posedge i_clk) i_rd <= 1; 133 | for(i=0; i<250; i=i+1) begin 134 | @(posedge i_clk) begin 135 | i_rd <= (i<249); 136 | end 137 | @(negedge i_clk) begin 138 | if(o_valid) begin 139 | test_input = test_queue.pop_back(); 140 | test_expected = convertGrey(test_input); 141 | assert(o_data == test_expected) 142 | else begin 143 | $display("Output data mismatch: \nExpected data = %h, Actual data = %h \n", 144 | test_expected, o_data); 145 | $stop; 146 | end 147 | end 148 | end 149 | end 150 | @(posedge i_clk) i_rd <= 0; 151 | assert(test_queue.size() == 0) 152 | else begin 153 | $display("Not all inputs read!"); 154 | $stop; 155 | end 156 | $display("Greyscale Mode Readback Test Passed."); 157 | repeat(5) @(posedge i_clk); 158 | $stop; 159 | end 160 | 161 | // 162 | // Asserts 163 | // 164 | 165 | // check that module never reads from empty input fifo 166 | property ibuf_rdEmpty_chk; 167 | @(posedge i_clk) disable iff(!i_rstn) 168 | (i_almostempty) |=> !o_rd; 169 | endproperty 170 | A_ibuf_rdEmpty_chk: assert property(ibuf_rdEmpty_chk) 171 | else $stop; 172 | 173 | // check that din_valid is asserted on each input fifo read 174 | property dinvalid_chk; 175 | @(posedge i_clk) disable iff(!i_rstn) 176 | (o_rd) |-> DUT.din_valid; 177 | endproperty 178 | A_mem_wr_chk: assert property(dinvalid_chk) 179 | else $stop; 180 | 181 | // check that o_valid issued one clock after read is issued 182 | property ovalid_chk1; 183 | @(posedge i_clk) 184 | (i_rd) |=> o_valid; 185 | endproperty 186 | A_ovalid_chk1: assert property(ovalid_chk1) 187 | else $stop; 188 | 189 | 190 | // check that o_valid never issued if fifo is empty 191 | property ovalid_chk2; 192 | @(posedge i_clk) 193 | (o_fill == 0) |=> !o_valid; 194 | endproperty 195 | A_ovalid_chk2: assert property(ovalid_chk2) 196 | else $stop; 197 | 198 | endmodule -------------------------------------------------------------------------------- /tb/ps_kernel_control_tb.sv: -------------------------------------------------------------------------------- 1 | 2 | module ps_kernel_control_tb(); 3 | 4 | 5 | logic clk; 6 | logic rstn; 7 | 8 | logic [7:0] i_data; 9 | logic i_valid; 10 | logic o_req; 11 | 12 | logic [23:0] o_r0_data; 13 | logic [23:0] o_r1_data; 14 | logic [23:0] o_r2_data; 15 | logic o_valid; 16 | 17 | ps_kernel_control DUT 18 | ( 19 | .i_clk (clk), 20 | .i_rstn (rstn), 21 | 22 | .i_data (i_data), 23 | .i_valid (i_valid), 24 | .o_req (o_req), 25 | 26 | .o_r0_data (o_r0_data), 27 | .o_r1_data (o_r1_data), 28 | .o_r2_data (o_r2_data), 29 | .o_valid (o_valid) 30 | ); 31 | 32 | always#(6) clk = ~clk; 33 | 34 | 35 | // 36 | integer test_counter = 0; 37 | integer i,j,k; 38 | logic [7:0] test_queue1 [$]; 39 | logic [7:0] test_queue2 [$]; 40 | logic [7:0] test_queue3 [$]; 41 | 42 | logic [23:0] test0_expected; 43 | logic [7:0] test0_data1, test0_data2, test0_data3; 44 | 45 | logic [23:0] test1_expected; 46 | logic [7:0] test1_data1, test1_data2, test1_data3; 47 | 48 | logic [23:0] test2_expected; 49 | logic [7:0] test2_data1, test2_data2, test2_data3; 50 | 51 | // 52 | task checkOutput_r0; 53 | input [7:0] queue [$]; 54 | begin 55 | for(j=0; j<640; j=j+1) begin 56 | @(negedge clk) begin 57 | // special case: first pixel in row 58 | if(j==0) begin 59 | test0_data1 = queue.pop_back(); 60 | test0_data2 = queue.pop_back(); 61 | test0_data3 = queue.pop_back(); 62 | test0_expected = {test0_data2, test0_data2, test0_data3}; 63 | assert(o_r0_data == test0_expected) 64 | else begin 65 | $error("Output data mismatch: Expected data = %h, Actual data = %h", test0_expected, o_r0_data); 66 | $stop; 67 | end 68 | end 69 | 70 | // special case: second pixel in row 71 | else if(j==1) begin 72 | test0_expected = {test0_data1, test0_data2, test0_data3}; 73 | assert(o_r0_data == test0_expected) 74 | else begin 75 | $error("Output data mismatch: Expected data = %h, Actual data = %h", test0_expected, o_r0_data); 76 | $stop; 77 | end 78 | end 79 | 80 | // special case: last pixel in row 81 | else if(j==639) begin 82 | test0_expected = {test0_data2, test0_data3, test0_data3}; 83 | assert(o_r0_data == test0_expected) 84 | else begin 85 | $error("Output data mismatch: Expected data = %h, Actual data = %h", test0_expected, o_r0_data); 86 | $stop; 87 | end 88 | end 89 | 90 | // default 91 | else begin 92 | test0_data1 = test0_data2; 93 | test0_data2 = test0_data3; 94 | test0_data3 = queue.pop_back(); 95 | test0_expected = {test0_data1, test0_data2, test0_data3}; 96 | assert(o_r0_data == test0_expected) 97 | else begin 98 | $error("Output data mismatch: Expected data = %h, Actual data = %h", test1_expected, o_r0_data); 99 | $stop; 100 | end 101 | end 102 | end 103 | end 104 | end 105 | endtask 106 | 107 | task checkOutput_r1; 108 | input [7:0] queue [$]; 109 | begin 110 | for(k=0; k<640; k=k+1) begin 111 | @(negedge clk) begin 112 | // special case: first pixel in row 113 | if(k==0) begin 114 | test1_data1 = queue.pop_back(); 115 | test1_data2 = queue.pop_back(); 116 | test1_data3 = queue.pop_back(); 117 | test1_expected = {test1_data2, test1_data2, test1_data3}; 118 | assert(o_r1_data == test1_expected) 119 | else begin 120 | $error("Output1 data mismatch: Expected data = %h, Actual data = %h", test1_expected, o_r1_data); 121 | $stop; 122 | end 123 | end 124 | 125 | // special case: second pixel in row 126 | else if(k==1) begin 127 | test1_expected = {test1_data1, test1_data2, test1_data3}; 128 | assert(o_r1_data == test1_expected) 129 | else begin 130 | $error("Output1 data mismatch: Expected data = %h, Actual data = %h", test1_expected, o_r1_data); 131 | $stop; 132 | end 133 | end 134 | 135 | // special case: last pixel in row 136 | else if(k==639) begin 137 | test1_expected = {test1_data2, test1_data3, test1_data3}; 138 | assert(o_r1_data == test1_expected) 139 | else begin 140 | $error("Output1 data mismatch: Expected data = %h, Actual data = %h", test1_expected, o_r1_data); 141 | $stop; 142 | end 143 | end 144 | 145 | // default 146 | else begin 147 | test1_data1 = test1_data2; 148 | test1_data2 = test1_data3; 149 | test1_data3 = queue.pop_back(); 150 | test1_expected = {test1_data1, test1_data2, test1_data3}; 151 | assert(o_r1_data == test1_expected) 152 | else begin 153 | $error("Output1 data mismatch: Expected data = %h, Actual data = %h", test1_expected, o_r1_data); 154 | $stop; 155 | end 156 | end 157 | end 158 | end 159 | end 160 | endtask 161 | 162 | task checkOutput_r2; 163 | input [7:0] queue [$]; 164 | begin 165 | for(i=0; i<640; i=i+1) begin 166 | @(negedge clk) begin 167 | // special case: first pixel in row 168 | if(i==0) begin 169 | test2_data1 = queue.pop_back(); 170 | test2_data2 = queue.pop_back(); 171 | test2_data3 = queue.pop_back(); 172 | test2_expected = {test2_data2, test2_data2, test2_data3}; 173 | assert(o_r2_data == test2_expected) 174 | else begin 175 | $error("Output2 data mismatch: Expected data = %h, Actual data = %h", test2_expected, o_r2_data); 176 | $stop; 177 | end 178 | end 179 | 180 | // special case: second pixel in row 181 | else if(i==1) begin 182 | test2_expected = {test2_data1, test2_data2, test2_data3}; 183 | assert(o_r2_data == test2_expected) 184 | else begin 185 | $error("Output2 data mismatch: Expected data = %h, Actual data = %h", test2_expected, o_r2_data); 186 | $stop; 187 | end 188 | end 189 | 190 | // special case: last pixel in row 191 | else if(i==639) begin 192 | test2_expected = {test2_data2, test2_data3, test2_data3}; 193 | assert(o_r2_data == test2_expected) 194 | else begin 195 | $error("Output2 data mismatch: Expected data = %h, Actual data = %h", test2_expected, o_r2_data); 196 | $stop; 197 | end 198 | end 199 | 200 | // default 201 | else begin 202 | test2_data1 = test2_data2; 203 | test2_data2 = test2_data3; 204 | test2_data3 = queue.pop_back(); 205 | test2_expected = {test2_data1, test2_data2, test2_data3}; 206 | assert(o_r2_data == test2_expected) 207 | else begin 208 | $error("Output2 data mismatch: Expected data = %h, Actual data = %h", test2_expected, o_r2_data); 209 | $stop; 210 | end 211 | end 212 | end 213 | end 214 | end 215 | endtask 216 | 217 | 218 | // 219 | 220 | // provide data on request 221 | always@(posedge clk) begin 222 | if(o_req) begin 223 | i_valid <= 1; 224 | i_data <= $urandom; 225 | 226 | if(test_counter < 1920) test_counter = test_counter+1; 227 | else test_counter = 0; 228 | 229 | if(test_counter <= 640) begin 230 | test_queue1.push_front(i_data); 231 | end 232 | else if(test_counter <= 1280) begin 233 | test_queue2.push_front(i_data); 234 | end 235 | else if(test_counter <= 1920) begin 236 | test_queue3.push_front(i_data); 237 | end 238 | end 239 | else begin 240 | i_valid <= 0; 241 | i_data <= 0; 242 | end 243 | end 244 | 245 | always@(posedge o_valid) begin 246 | 247 | fork 248 | // thread 1 249 | checkOutput_r0(test_queue1); 250 | 251 | // thread 2 252 | begin 253 | for(i=0; i<640; i=i+1) begin 254 | @(negedge clk) begin 255 | assert(o_r1_data == test0_expected) 256 | else begin 257 | $error("Output1 data mismatch: Expected data = %h, Actual data = %h", test0_expected, o_r1_data); 258 | $stop; 259 | end 260 | end 261 | end 262 | end 263 | 264 | // thread 3 265 | checkOutput_r2(test_queue2); 266 | join 267 | end 268 | 269 | initial begin 270 | clk = 0; 271 | rstn = 0; 272 | i_data = 0; 273 | i_valid = 0; 274 | #100; 275 | rstn = 1; 276 | end 277 | 278 | endmodule -------------------------------------------------------------------------------- /tb/tb.sv: -------------------------------------------------------------------------------- 1 | // for commit ec10b6b 2 | 3 | module tb(); 4 | 5 | logic i_sysclk = 0; 6 | logic i_rst; 7 | 8 | logic o_cam_xclk; 9 | logic o_cam_rstn; 10 | logic o_cam_pwdn; 11 | 12 | logic i_cam_pclk = 0; 13 | logic i_cam_vsync; 14 | logic i_cam_href; 15 | logic [7:0] i_cam_data; 16 | 17 | wire SCL, SDA; 18 | pullup(SCL); 19 | pullup(SDA); 20 | 21 | logic [3:0] o_TMDS_P, o_TMDS_N; 22 | 23 | logic [11:0] test_data; 24 | 25 | sys_top DUT( 26 | .i_sysclk (i_sysclk), 27 | .i_rst (i_rst), 28 | 29 | .o_cam_xclk (o_cam_xclk), 30 | .o_cam_rstn (o_cam_rstn), 31 | .o_cam_pwdn (o_cam_pwdn), 32 | 33 | .i_cam_pclk (i_cam_pclk), 34 | .i_cam_vsync (i_cam_vsync), 35 | .i_cam_href (i_cam_href), 36 | .i_cam_data (i_cam_data), 37 | 38 | .SCL (SCL), 39 | .SDA (SDA), 40 | 41 | .btn_mode (1'b0), 42 | .sw_gaussian (1'b0), 43 | 44 | .o_TMDS_P (o_TMDS_P), 45 | .o_TMDS_N (o_TMDS_N) 46 | ); 47 | 48 | // Testbench Setup 49 | // 50 | localparam TESTRUNS = 5; // # of frames 51 | localparam ROWCOUNT = 480; // # of rows 52 | localparam ROWLENGTH = 1280; // # of bytes per line (pixels*2) 53 | // 54 | int rows; 55 | int pixels; 56 | 57 | // test data 58 | logic [11:0] test_queue[$]; 59 | logic [11:0] test_expected; 60 | 61 | // setup clocks 62 | localparam SYSCLK_PERIOD = 8; 63 | localparam CAM_PCLK_PERIOD = 20; 64 | 65 | always#(SYSCLK_PERIOD/2) i_sysclk = ~i_sysclk; 66 | always#(CAM_PCLK_PERIOD/2) i_cam_pclk = ~i_cam_pclk; 67 | 68 | 69 | // vsync pulse 70 | task startFrame; 71 | begin 72 | i_cam_vsync = 0; 73 | @(posedge i_cam_pclk); 74 | i_cam_vsync = 1; 75 | repeat(4704) @(posedge i_cam_pclk); // mimic vsync pulse 76 | i_cam_vsync = 0; 77 | repeat(26656) @(posedge i_cam_pclk); // mimic vsync back porch 78 | end 79 | endtask 80 | 81 | 82 | // 83 | // Testbench 84 | // 85 | initial begin 86 | i_rst = 1; 87 | i_cam_vsync = 0; 88 | i_cam_href = 0; 89 | i_cam_data = 0; 90 | repeat(6) @(negedge i_cam_pclk); 91 | 92 | i_rst = 0; 93 | 94 | repeat(17) @(posedge i_cam_pclk); 95 | 96 | // repeat for # of frames 97 | for(int i=0; i0) begin 183 | assert(t_mem_waddr == ($past(t_mem_waddr)+1)) 184 | else begin 185 | $error("BRAM waddr check failed: Expected data = %b, Actual data = %b", 186 | ($past(DUT.mem_i.mem_waddr)+1), DUT.mem_i.mem_waddr); 187 | $stop; 188 | end 189 | end 190 | else if($past(t_mem_waddr) == 307199) begin 191 | assert(DUT.mem_i.mem_waddr == 0) 192 | else begin 193 | $error("BRAM waddr check failed: Expected data = %b, Actual data = %b", 194 | 0, DUT.mem_i.mem_waddr); 195 | $stop; 196 | end 197 | end 198 | end 199 | end 200 | 201 | 202 | // check display interface read data 203 | // 204 | always@(posedge DUT.clk_25MHz) begin 205 | if((DUT.display_i.active) && (DUT.display_i.STATE == 2)) begin 206 | test_expected = test_queue.pop_back(); 207 | // $display("Expected data: %h, Actual data: %h", test_expected, display_i.i_rgb); 208 | assert(DUT.display_i.ibuf_rdata == test_expected) 209 | else begin 210 | $error("Checking failed: Expected data = %h, Actual data = %h", test_expected, DUT.display_i.ibuf_rdata); 211 | $stop; 212 | end 213 | 214 | end 215 | end 216 | 217 | endmodule -------------------------------------------------------------------------------- /tb/vtc_tb.v: -------------------------------------------------------------------------------- 1 | module vtc_tb(); 2 | 3 | 4 | reg clk = 0; 5 | reg i_rstn = 0; 6 | 7 | wire vsync, hsync, active; 8 | 9 | wire [9:0] counterX, counterY; 10 | 11 | 12 | localparam CLK_PERIOD = 40; 13 | always#(CLK_PERIOD/2) clk <= ~clk; 14 | 15 | vtc DUT( 16 | .i_clk (clk), 17 | .i_rstn (rstn), 18 | .o_vsync (vsync), 19 | .o_hsync (hsync), 20 | .o_active (active), 21 | .o_counterX (counterX), 22 | .o_counterY (counterY) 23 | ); 24 | 25 | initial begin 26 | $dumpfile("vtc.vcd"); 27 | $dumpvars(0, vtc_tb); 28 | end 29 | 30 | initial begin 31 | #100; 32 | i_rstn = 1; 33 | 34 | repeat(900) begin 35 | @(posedge clk); 36 | end 37 | 38 | $finish; 39 | end 40 | 41 | endmodule // vtc_tb -------------------------------------------------------------------------------- /test.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a general .xdc for the Zybo Z7 Rev. B 2 | ## It is compatible with the Zybo Z7-20 and Zybo Z7-10 3 | ## To use it in a project: 4 | ## - uncomment the lines corresponding to used pins 5 | ## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project 6 | 7 | ##Clock signal 8 | set_property -dict {PACKAGE_PIN K17 IOSTANDARD LVCMOS33} [get_ports i_sysclk] 9 | #create_clock -add -name sys_clk_pin -period 8.00 -waveform {0 4} [get_ports { sysclk }]; 10 | 11 | 12 | ##Switches 13 | set_property -dict { PACKAGE_PIN G15 IOSTANDARD LVCMOS33 } [get_ports { sw_gaussian }]; #IO_L19N_T3_VREF_35 Sch=sw[0] 14 | set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { sw_sobel }]; #IO_L24P_T3_34 Sch=sw[1] 15 | set_property -dict { PACKAGE_PIN W13 IOSTANDARD LVCMOS33 } [get_ports { sw_freeze }]; #IO_L4N_T0_34 Sch=sw[2] 16 | #set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L9P_T1_DQS_34 Sch=sw[3] 17 | 18 | 19 | ##Buttons 20 | set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS33} [get_ports i_rst] 21 | set_property -dict {PACKAGE_PIN P16 IOSTANDARD LVCMOS33} [get_ports btn_mode] 22 | set_property -dict { PACKAGE_PIN K19 IOSTANDARD LVCMOS33 } [get_ports { btn_decSobel }]; #IO_L10P_T1_AD11P_35 Sch=btn[2] 23 | set_property -dict { PACKAGE_PIN Y16 IOSTANDARD LVCMOS33 } [get_ports { btn_incSobel }]; #IO_L7P_T1_34 Sch=btn[3] 24 | 25 | 26 | ##LEDs 27 | set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports {led_gaussian}] 28 | set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports {led_sobel}] 29 | set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led_threshold}]; #IO_0_35 Sch=led[2] 30 | #set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L3N_T0_DQS_AD1N_35 Sch=led[3] 31 | 32 | 33 | ##RGB LED 5 (Zybo Z7-20 only) 34 | set_property -dict { PACKAGE_PIN Y11 IOSTANDARD LVCMOS33 } [get_ports { led_mode }]; #IO_L18N_T2_13 Sch=led5_r 35 | #set_property -dict { PACKAGE_PIN T5 IOSTANDARD LVCMOS33 } [get_ports { led5_g }]; #IO_L19P_T3_13 Sch=led5_g 36 | #set_property -dict { PACKAGE_PIN Y12 IOSTANDARD LVCMOS33 } [get_ports { led5_b }]; #IO_L20P_T3_13 Sch=led5_b 37 | 38 | ##RGB LED 6 39 | #set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { led6_r }]; #IO_L18P_T2_34 Sch=led6_r 40 | #set_property -dict { PACKAGE_PIN F17 IOSTANDARD LVCMOS33 } [get_ports { led6_g }]; #IO_L6N_T0_VREF_35 Sch=led6_g 41 | #set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { led6_b }]; #IO_L8P_T1_AD10P_35 Sch=led6_b 42 | 43 | 44 | 45 | ##USB-OTG over-current detect pin 46 | #set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { otg_oc }]; #IO_L3P_T0_DQS_PUDC_B_34 Sch=otg_oc 47 | 48 | 49 | ##Fan (Zybo Z7-20 only) 50 | #set_property -dict { PACKAGE_PIN Y13 IOSTANDARD LVCMOS33 PULLUP true } [get_ports { fan_fb_pu }]; #IO_L20N_T3_13 Sch=fan_fb_pu 51 | 52 | 53 | ##HDMI TX 54 | #set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_hpd }]; #IO_L5P_T0_AD9P_35 Sch=hdmi_tx_hpd 55 | #set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_scl }]; #IO_L16P_T2_35 Sch=hdmi_tx_scl 56 | #set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_sda }]; #IO_L16N_T2_35 Sch=hdmi_tx_sda 57 | set_property -dict {PACKAGE_PIN H17 IOSTANDARD TMDS_33} [get_ports {o_TMDS_N[3]}] 58 | set_property -dict {PACKAGE_PIN H16 IOSTANDARD TMDS_33} [get_ports {o_TMDS_P[3]}] 59 | set_property -dict {PACKAGE_PIN D20 IOSTANDARD TMDS_33} [get_ports {o_TMDS_N[0]}] 60 | set_property -dict {PACKAGE_PIN D19 IOSTANDARD TMDS_33} [get_ports {o_TMDS_P[0]}] 61 | set_property -dict {PACKAGE_PIN B20 IOSTANDARD TMDS_33} [get_ports {o_TMDS_N[1]}] 62 | set_property -dict {PACKAGE_PIN C20 IOSTANDARD TMDS_33} [get_ports {o_TMDS_P[1]}] 63 | set_property -dict {PACKAGE_PIN A20 IOSTANDARD TMDS_33} [get_ports {o_TMDS_N[2]}] 64 | set_property -dict {PACKAGE_PIN B19 IOSTANDARD TMDS_33} [get_ports {o_TMDS_P[2]}] 65 | 66 | ##HDMI TX CEC 67 | #set_property -dict { PACKAGE_PIN E19 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_cec }]; #IO_L5N_T0_AD9N_35 Sch=hdmi_tx_cec 68 | 69 | 70 | ##Pmod Header JC -> OV7670 data in 71 | set_property -dict {PACKAGE_PIN V15 IOSTANDARD LVCMOS33} [get_ports {i_cam_data[0]}] 72 | set_property -dict {PACKAGE_PIN W15 IOSTANDARD LVCMOS33} [get_ports {i_cam_data[1]}] 73 | set_property -dict {PACKAGE_PIN T11 IOSTANDARD LVCMOS33} [get_ports {i_cam_data[2]}] 74 | set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports {i_cam_data[3]}] 75 | set_property -dict {PACKAGE_PIN W14 IOSTANDARD LVCMOS33} [get_ports {i_cam_data[4]}] 76 | set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVCMOS33} [get_ports {i_cam_data[5]}] 77 | set_property -dict {PACKAGE_PIN T12 IOSTANDARD LVCMOS33} [get_ports {i_cam_data[6]}] 78 | set_property -dict {PACKAGE_PIN U12 IOSTANDARD LVCMOS33} [get_ports {i_cam_data[7]}] 79 | 80 | 81 | ##Pmod Header JD -> OV7670 control 82 | set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports o_cam_xclk] 83 | set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports o_cam_rstn] 84 | set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports i_cam_vsync] 85 | set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports i_cam_href] 86 | set_property -dict {PACKAGE_PIN U14 IOSTANDARD LVCMOS33} [get_ports i_cam_pclk] 87 | set_property -dict {PACKAGE_PIN U15 IOSTANDARD LVCMOS33} [get_ports o_cam_pwdn] 88 | set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports SCL] 89 | set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports SDA] 90 | 91 | 92 | ##Pcam MIPI CSI-2 Connector 93 | ## This configuration expects the sensor to use 672Mbps/lane = 336 MHz HS_Clk 94 | #create_clock -period 2.976 -name dphy_hs_clock_clk_p -waveform {0.000 1.488} [get_ports dphy_hs_clock_clk_p] 95 | #set_property INTERNAL_VREF 0.6 [get_iobanks 35] 96 | #set_property -dict { PACKAGE_PIN J19 IOSTANDARD HSUL_12 } [get_ports { dphy_clk_lp_n }]; #IO_L10N_T1_AD11N_35 Sch=lp_clk_n 97 | #set_property -dict { PACKAGE_PIN H20 IOSTANDARD HSUL_12 } [get_ports { dphy_clk_lp_p }]; #IO_L17N_T2_AD5N_35 Sch=lp_clk_p 98 | #set_property -dict { PACKAGE_PIN M18 IOSTANDARD HSUL_12 } [get_ports { dphy_data_lp_n[0] }]; #IO_L8N_T1_AD10N_35 Sch=lp_lane_n[0] 99 | #set_property -dict { PACKAGE_PIN L19 IOSTANDARD HSUL_12 } [get_ports { dphy_data_lp_p[0] }]; #IO_L9P_T1_DQS_AD3P_35 Sch=lp_lane_p[0] 100 | #set_property -dict { PACKAGE_PIN L20 IOSTANDARD HSUL_12 } [get_ports { dphy_data_lp_n[1] }]; #IO_L9N_T1_DQS_AD3N_35 Sch=lp_lane_n[1] 101 | #set_property -dict { PACKAGE_PIN J20 IOSTANDARD HSUL_12 } [get_ports { dphy_data_lp_p[1] }]; #IO_L17P_T2_AD5P_35 Sch=lp_lane_p[1] 102 | #set_property -dict { PACKAGE_PIN H18 IOSTANDARD LVDS_25 } [get_ports { dphy_hs_clock_clk_n }]; #IO_L14N_T2_AD4N_SRCC_35 Sch=mipi_clk_n 103 | #set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVDS_25 } [get_ports { dphy_hs_clock_clk_p }]; #IO_L14P_T2_AD4P_SRCC_35 Sch=mipi_clk_p 104 | #set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVDS_25 } [get_ports { dphy_data_hs_n[0] }]; #IO_L7N_T1_AD2N_35 Sch=mipi_lane_n[0] 105 | #set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVDS_25 } [get_ports { dphy_data_hs_p[0] }]; #IO_L7P_T1_AD2P_35 Sch=mipi_lane_p[0] 106 | #set_property -dict { PACKAGE_PIN L17 IOSTANDARD LVDS_25 } [get_ports { dphy_data_hs_n[1] }]; #IO_L11N_T1_SRCC_35 Sch=mipi_lane_n[1] 107 | #set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVDS_25 } [get_ports { dphy_data_hs_p[1] }]; #IO_L11P_T1_SRCC_35 Sch=mipi_lane_p[1] 108 | #set_property -dict { PACKAGE_PIN G19 IOSTANDARD LVCMOS33 } [get_ports { cam_clk }]; #IO_L18P_T2_AD13P_35 Sch=cam_clk 109 | #set_property -dict { PACKAGE_PIN G20 IOSTANDARD LVCMOS33 PULLUP true} [get_ports { cam_gpio }]; #IO_L18N_T2_AD13N_35 Sch=cam_gpio 110 | #set_property -dict { PACKAGE_PIN F20 IOSTANDARD LVCMOS33 } [get_ports { cam_scl }]; #IO_L15N_T2_DQS_AD12N_35 Sch=cam_scl 111 | #set_property -dict { PACKAGE_PIN F19 IOSTANDARD LVCMOS33 } [get_ports { cam_sda }]; #IO_L15P_T2_DQS_AD12P_35 Sch=cam_sda 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | create_clock -period 41.167 -name cam_pclk -waveform {0.000 20.584} -add [get_ports i_cam_pclk] 121 | 122 | 123 | set_false_path -from [get_clocks cam_pclk] -to [get_clocks -of_objects [get_pins dcm_i/inst/mmcm_adv_inst/CLKOUT0]] 124 | set_false_path -from [get_clocks cam_pclk] -to [get_clocks -of_objects [get_pins dcm_i/inst/mmcm_adv_inst/CLKOUT3]] 125 | 126 | 127 | 128 | set_max_delay -from [get_clocks cam_pclk] -to [get_clocks -of_objects [get_pins dcm_i/inst/mmcm_adv_inst/CLKOUT1]] 42.000 129 | set_max_delay -from [get_clocks cam_pclk] -to [get_clocks -of_objects [get_pins dcm_i/inst/mmcm_adv_inst/CLKOUT2]] 14.000 130 | 131 | set_false_path -from [get_clocks cam_pclk] -to [get_clocks -of_objects [get_pins dcm_i/inst/mmcm_adv_inst/CLKOUT1]] 132 | set_false_path -from [get_clocks cam_pclk] -to [get_clocks -of_objects [get_pins dcm_i/inst/mmcm_adv_inst/CLKOUT2]] 133 | set_max_delay -from [get_clocks -of_objects [get_pins dcm_i/inst/mmcm_adv_inst/CLKOUT2]] -to [get_clocks cam_pclk] 13.000 134 | 135 | 136 | 137 | set_max_delay -from [get_clocks -of_objects [get_pins dcm_i/inst/mmcm_adv_inst/CLKOUT3]] -to [get_clocks cam_pclk] 6.667 138 | --------------------------------------------------------------------------------