├── LICENSE-2.0.txt ├── README.md ├── docs ├── fb_verilator.png └── xor.jpg ├── rtl ├── .gitignore ├── Makefile ├── VgaSyncGen.v ├── icebreaker.pcf ├── test.gtkw ├── top.v ├── top_tb.v └── xor.v └── sim └── fb_verilator.cpp /LICENSE-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XOR video fun on an FPGA 2 | 3 | Saw this: https://hackaday.com/2021/04/13/alien-art-drawn-with-surprisingly-simple-math/ 4 | 5 | The magic line is: 6 | 7 | assign rrggbb = ((x_px ^ y_px) % 10'd9) == 1 ? 6'b111111 : 6'b000000; 8 | 9 | And made an [FPGA implementation](rtl/xor.v). 10 | 11 | ![xor demo](docs/xor.jpg) 12 | 13 | ## Simulation instructions 14 | 15 | Ensure that you have libsdl2-dev and verilator installed. 16 | 17 | sudo apt-get install libsdl2-dev libsdl2-image-dev verilator 18 | 19 | To run the simulation use the following commands: 20 | 21 | cd rtl 22 | make verilator && ./obj_dir/Vxor 23 | 24 | ![fb_verilator](docs/fb_verilator.png) 25 | 26 | 27 | ## FPGA Build instructions 28 | 29 | It's setup to run on [1 Bit Squared icebreaker](https://1bitsquared.com/products/icebreaker) with my [VGA pmod](https://github.com/mattvenn/6bit-pmod-vga) plugged into pmod1a. 30 | 31 | type 32 | 33 | make prog 34 | 35 | to build & upload to the icebreaker 36 | 37 | ## License 38 | 39 | This software and hardware is licensed under the [Apache License version 2](LICENSE-2.0.txt) 40 | -------------------------------------------------------------------------------- /docs/fb_verilator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattvenn/xor_vga_fpga/1fd00b155d253505d44124ec649e13e262e99402/docs/fb_verilator.png -------------------------------------------------------------------------------- /docs/xor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattvenn/xor_vga_fpga/1fd00b155d253505d44124ec649e13e262e99402/docs/xor.jpg -------------------------------------------------------------------------------- /rtl/.gitignore: -------------------------------------------------------------------------------- 1 | *log 2 | *vcd 3 | *out 4 | *swp 5 | *hex 6 | *asc 7 | *bin 8 | *json 9 | obj_dir/ 10 | -------------------------------------------------------------------------------- /rtl/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /bin/bash # Use bash syntax 2 | SEED = 10 3 | PROJECT = xor 4 | 5 | DEVICE = up5k 6 | PIN_DEF = icebreaker.pcf 7 | PACKAGE = sg48 8 | 9 | # target freq for vga panel 10 | FREQ = 31.5 11 | 12 | all: $(PROJECT).bin 13 | 14 | BUILD_DIR = ./ 15 | SOURCES = VgaSyncGen.v top.v xor.v 16 | 17 | # $@ The file name of the target of the rule.rule 18 | # $< first pre requisite 19 | # $^ names of all preerquisites 20 | 21 | CFLAGS = -O3 -Iobj_dir -I/usr/share/verilator/include 22 | 23 | LDFLAGS = -lSDL2 -lSDL2_image 24 | 25 | # rules for building the json 26 | %.json: $(SOURCES) $(LISTINGS) 27 | yosys -l yosys.log -DSYNTH -p 'synth_ice40 -top top -json $(PROJECT).json' $(SOURCES) 28 | 29 | %.asc: %.json $(ICEBREAKER_PIN_DEF) 30 | nextpnr-ice40 -l nextpnr.log --seed $(SEED) --freq $(FREQ) --package $(PACKAGE) --$(DEVICE) --asc $@ --pcf $(PIN_DEF) --json $< 31 | 32 | gui: $(PROJECT).json $(ICEBREAKER_PIN_DEF) 33 | nextpnr-ice40 --gui -l nextpnr.log --seed $(SEED) --freq $(FREQ) --package $(PACKAGE) --$(DEVICE) --asc $(PROJECT).asc --pcf $(PIN_DEF) --json $(PROJECT).json 34 | 35 | # bin, for programming 36 | $(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.asc 37 | icepack $< $@ 38 | 39 | prog: $(PROJECT).bin 40 | iceprog $< 41 | 42 | debug: 43 | iverilog -o test.out $(SOURCES) top_tb.v -DDEBUG 44 | vvp test.out -fst 45 | gtkwave test.vcd test.gtkw 46 | 47 | obj_dir/Vxor.h : $(SOURCES) $(LISTINGS) ../sim/fb_verilator.cpp 48 | verilator --cc xor.v --exe ../sim/fb_verilator.cpp -CFLAGS "$(CFLAGS)" -LDFLAGS "$(LDFLAGS)" 49 | 50 | verilator: obj_dir/Vxor.h 51 | cd obj_dir && make -f Vxor.mk 52 | 53 | clean: 54 | rm -f ${PROJECT}.json ${PROJECT}.asc ${PROJECT}.bin *log $(LISTINGS) 55 | rm -rf obj_dir 56 | 57 | #secondary needed or make will remove useful intermediate files 58 | .SECONDARY: 59 | .PHONY: all clean 60 | -------------------------------------------------------------------------------- /rtl/VgaSyncGen.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: Ridotech 4 | // Engineer: Juan Manuel Rico 5 | // 6 | // Create Date: 09:34:23 30/09/2017 7 | // Module Name: vga_controller 8 | // Description: Basic control for 640x480@72Hz VGA signal. 9 | // 10 | // Dependencies: 11 | // 12 | // Revision: 13 | // Revision 0.01 - File Created for Roland Coeurjoly (RCoeurjoly) in 640x480@85Hz. 14 | // Revision 0.02 - Change for 640x480@60Hz. 15 | // Revision 0.03 - Solved some mistakes. 16 | // Revision 0.04 - Change for 640x480@72Hz and output signals 'activevideo' 17 | // and 'px_clk'. 18 | // 19 | // Additional Comments: 20 | // 21 | ////////////////////////////////////////////////////////////////////////////////// 22 | module VgaSyncGen ( 23 | input wire px_clk, // Input clock: 31.5MHz 24 | input wire reset, // reset 25 | output wire hsync, // Horizontal sync out 26 | output wire vsync, // Vertical sync out 27 | output reg [9:0] x_px, // X position for actual pixel. 28 | output reg [9:0] y_px, // Y position for actual pixel. 29 | output wire activevideo 30 | ); 31 | 32 | /* 33 | http://www.epanorama.net/faq/vga2rgb/calc.html 34 | [*User-Defined_mode,(640X480)] 35 | PIXEL_CLK = 31500 36 | H_DISP = 640 37 | V_DISP = 480 38 | H_FPORCH = 24 39 | H_SYNC = 40 40 | H_BPORCH = 128 41 | V_FPORCH = 9 42 | V_SYNC = 3 43 | V_BPORCH = 28 44 | */ 45 | 46 | // Video structure constants. 47 | parameter activeHvideo = 640; // Width of visible pixels. 48 | parameter activeVvideo = 480; // Height of visible lines. 49 | parameter hfp = 24; // Horizontal front porch length. 50 | parameter hpulse = 40; // Hsync pulse length. 51 | parameter hbp = 128; // Horizontal back porch length. 52 | parameter vfp = 9; // Vertical front porch length. 53 | parameter vpulse = 3; // Vsync pulse length. 54 | parameter vbp = 28; // Vertical back porch length. 55 | parameter blackH = hfp + hpulse + hbp; // Hide pixels in one line. 56 | parameter blackV = vfp + vpulse + vbp; // Hide lines in one frame. 57 | parameter hpixels = blackH + activeHvideo; // Total horizontal pixels. 58 | parameter vlines = blackV + activeVvideo; // Total lines. 59 | 60 | // Registers for storing the horizontal & vertical counters. 61 | reg [9:0] hc; 62 | reg [9:0] vc; 63 | 64 | // Initial values. 65 | initial 66 | begin 67 | x_px = 0; 68 | y_px = 0; 69 | hc = 0; 70 | vc = 0; 71 | end 72 | 73 | // Counting pixels. 74 | always @(posedge px_clk) 75 | begin 76 | if(reset) begin 77 | hc <= 0; 78 | vc <= 0; 79 | end else begin 80 | // Keep counting until the end of the line. 81 | if (hc < hpixels - 1) 82 | hc <= hc + 1; 83 | else 84 | // When we hit the end of the line, reset the horizontal 85 | // counter and increment the vertical counter. 86 | // If vertical counter is at the end of the frame, then 87 | // reset that one too. 88 | begin 89 | hc <= 0; 90 | if (vc < vlines - 1) 91 | vc <= vc + 1; 92 | else 93 | vc <= 0; 94 | end 95 | end 96 | end 97 | 98 | // Generate sync pulses (active low) and active video. 99 | assign hsync = (hc >= hfp && hc < hfp + hpulse) ? 0:1; 100 | assign vsync = (vc >= vfp && vc < vfp + vpulse) ? 0:1; 101 | assign activevideo = (hc >= blackH && vc >= blackV) ? 1:0; 102 | 103 | // Generate color. 104 | always @(posedge px_clk) 105 | begin 106 | if(reset) begin 107 | x_px <= 0; 108 | y_px <= 0; 109 | end else begin 110 | x_px <= hc - blackH; 111 | y_px <= vc - blackV; 112 | end 113 | end 114 | endmodule 115 | `default_nettype wire 116 | -------------------------------------------------------------------------------- /rtl/icebreaker.pcf: -------------------------------------------------------------------------------- 1 | # 12 MHz clock 2 | set_io -nowarn clk 35 3 | 4 | # RS232 5 | set_io -nowarn RX 6 6 | set_io -nowarn TX 9 7 | 8 | # LEDs and Button 9 | set_io -nowarn reset_n 10 10 | set_io -nowarn LEDR_N 11 11 | set_io -nowarn LEDG_N 37 12 | 13 | # pmod buttons 14 | set_io -nowarn but1 20 15 | set_io -nowarn but2 19 16 | set_io -nowarn but3 18 17 | 18 | # RGB LED Driver 19 | set_io -nowarn LED_RED_N 39 20 | set_io -nowarn LED_GRN_N 40 21 | set_io -nowarn LED_BLU_N 41 22 | 23 | # SPI Flash 24 | set_io -nowarn FLASH_SCK 15 25 | set_io -nowarn FLASH_SSB 16 26 | set_io -nowarn FLASH_IO0 14 27 | set_io -nowarn FLASH_IO1 17 28 | set_io -nowarn FLASH_IO2 12 29 | set_io -nowarn FLASH_IO3 13 30 | 31 | set_io -nowarn hsync 47 32 | set_io -nowarn vsync 45 33 | set_io -nowarn rrggbb[5] 3 34 | set_io -nowarn rrggbb[4] 48 35 | set_io -nowarn rrggbb[3] 46 36 | set_io -nowarn rrggbb[2] 44 37 | set_io -nowarn rrggbb[1] 4 38 | set_io -nowarn rrggbb[0] 2 39 | 40 | # PMOD 1A 41 | set_io -nowarn P1A1 4 42 | set_io -nowarn P1A2 2 43 | set_io -nowarn P1A3 47 44 | set_io -nowarn P1A4 45 45 | set_io -nowarn P1A7 3 46 | set_io -nowarn P1A8 48 47 | set_io -nowarn P1A9 46 48 | set_io -nowarn P1A10 44 49 | 50 | # PMOD 1B 51 | set_io -nowarn P1B1 43 52 | set_io -nowarn P1B2 38 53 | set_io -nowarn P1B3 34 54 | set_io -nowarn P1B4 31 55 | set_io -nowarn P1B7 42 56 | set_io -nowarn P1B8 36 57 | set_io -nowarn P1B9 32 58 | set_io -nowarn P1B10 28 59 | 60 | # PMOD 2 61 | #PMOD MIC3 62 | set_io -nowarn adc_mic_cs 26 63 | set_io -nowarn adc_mic_sd 20 64 | set_io -nowarn adc_mic_clk 18 65 | 66 | #PMOD MATT ADC 67 | #set_io -nowarn adc_mic_cs 26 68 | #set_io -nowarn adc_mic_sd 23 69 | #set_io -nowarn adc_mic_clk 20 70 | 71 | 72 | set_io -nowarn P2_1 27 73 | set_io -nowarn P2_2 25 74 | set_io -nowarn P2_3 21 75 | set_io -nowarn P2_4 19 76 | set_io -nowarn P2_7 26 77 | set_io -nowarn P2_8 23 78 | set_io -nowarn P2_9 20 79 | set_io -nowarn P2_10 18 80 | 81 | # LEDs and Buttons (PMOD 2) 82 | set_io -nowarn LED1 27 83 | set_io -nowarn LED2 25 84 | set_io -nowarn LED3 21 85 | set_io -nowarn LED5 26 86 | set_io -nowarn LED4 23 87 | set_io -nowarn BTN1 20 88 | set_io -nowarn BTN2 19 89 | set_io -nowarn BTN3 18 90 | 91 | -------------------------------------------------------------------------------- /rtl/test.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Mon Apr 19 14:36:36 2021 4 | [*] 5 | [dumpfile] "/home/matt/work/fpga/xor_vga_fpga/rtl/test.vcd" 6 | [dumpfile_mtime] "Mon Apr 19 14:36:11 2021" 7 | [dumpfile_size] 14237 8 | [savefile] "/home/matt/work/fpga/xor_vga_fpga/rtl/test.gtkw" 9 | [timestart] 0 10 | [size] 1000 973 11 | [pos] -1 -1 12 | *-17.000000 -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 -1 13 | [treeopen] test. 14 | [sst_width] 273 15 | [signals_width] 228 16 | [sst_expanded] 1 17 | [sst_vpaned_height] 267 18 | @28 19 | test.top_0.clk 20 | test.top_0.hsync 21 | test.top_0.vsync 22 | test.top_0.px_clk 23 | test.top_0.reset_n 24 | @23 25 | test.top_0.rrggbb[5:0] 26 | [pattern_trace] 1 27 | [pattern_trace] 0 28 | -------------------------------------------------------------------------------- /rtl/top.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | 3 | module top ( 4 | input wire clk , 5 | input wire reset_n, 6 | input wire but1, 7 | input wire but2, 8 | input wire but3, 9 | output wire hsync , 10 | output wire vsync , 11 | output wire [5:0] rrggbb 12 | ); 13 | 14 | wire px_clk; 15 | 16 | // Generated values for pixel clock of 31.5Mhz and 72Hz frame frecuency. 17 | // # icepll -i12 -o31.5 18 | // 19 | // F_PLLIN: 12.000 MHz (given) 20 | // F_PLLOUT: 31.500 MHz (requested) 21 | // F_PLLOUT: 31.500 MHz (achieved) 22 | // 23 | // FEEDBACK: SIMPLE 24 | // F_PFD: 12.000 MHz 25 | // F_VCO: 1008.000 MHz 26 | // 27 | // DIVR: 0 (4'b0000) 28 | // DIVF: 83 (7'b1010011) 29 | // DIVQ: 5 (3'b101) 30 | // 31 | // FILTER_RANGE: 1 (3'b001) 32 | // 33 | `ifdef SYNTH 34 | SB_PLL40_PAD #( 35 | .FEEDBACK_PATH("SIMPLE" ), 36 | .DIVR (4'b0000 ), 37 | .DIVF (7'b1010011), 38 | .DIVQ (3'b101 ), 39 | .FILTER_RANGE (3'b001 ) 40 | ) uut ( 41 | .RESETB (1'b1 ), 42 | .BYPASS (1'b0 ), 43 | .PACKAGEPIN(clk ), 44 | .PLLOUTCORE(px_clk) 45 | ); 46 | `else 47 | assign px_clk = clk; 48 | `endif 49 | 50 | xor_vga i_xor_vga ( 51 | .clk (px_clk ), 52 | .reset_n(reset_n), 53 | .but1 (but1 ), 54 | .but2 (but2 ), 55 | .but3 (but3 ), 56 | .hsync (hsync ), 57 | .vsync (vsync ), 58 | .rrggbb (rrggbb ) 59 | ); 60 | 61 | endmodule 62 | -------------------------------------------------------------------------------- /rtl/top_tb.v: -------------------------------------------------------------------------------- 1 | module test; 2 | 3 | reg clk = 0; 4 | reg px_clk = 0; 5 | reg reset_n = 0; 6 | localparam DAY = 60 * 60 * 60; 7 | 8 | initial begin 9 | $dumpfile("test.vcd"); 10 | $dumpvars(0,test); 11 | # 4 12 | reset_n = 1; 13 | # DAY; 14 | $finish; 15 | end 16 | 17 | top top_0(.clk(px_clk), .reset_n(reset_n)); 18 | always #4 clk = !clk; 19 | always #1 px_clk = !px_clk; 20 | 21 | endmodule 22 | -------------------------------------------------------------------------------- /rtl/xor.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | module xor_vga ( 3 | input wire clk, 4 | input wire reset_n, 5 | input wire but1, 6 | input wire but2, 7 | input wire but3, 8 | output wire hsync, 9 | output wire vsync, 10 | output wire [5:0] rrggbb 11 | ); 12 | 13 | wire reset = !reset_n; 14 | 15 | wire [9:0] x_px; // X position for actual pixel. 16 | wire [9:0] y_px; // Y position for actual pixel. 17 | 18 | // the magic 19 | assign rrggbb = ((x_px ^ y_px) % 10'd9) == 1 ? 6'b111111 : 6'b000000; 20 | 21 | // the VGA module 22 | wire activevideo; 23 | wire px_clk; 24 | assign px_clk = clk; 25 | VgaSyncGen vga_0 (.px_clk(px_clk), .hsync(hsync), .vsync(vsync), .x_px(x_px), .y_px(y_px), .activevideo(activevideo), .reset(reset)); 26 | 27 | endmodule 28 | `default_nettype wire 29 | -------------------------------------------------------------------------------- /sim/fb_verilator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "Vxor.h" 9 | #include "verilated.h" 10 | 11 | #define WINDOW_WIDTH 640 12 | #define WINDOW_HEIGHT 480 13 | 14 | int main(int argc, char **argv) { 15 | 16 | std::vector< uint8_t > framebuffer(WINDOW_WIDTH * WINDOW_HEIGHT * 4, 0); 17 | 18 | Verilated::commandArgs(argc, argv); 19 | 20 | Vxor *top = new Vxor; 21 | 22 | // perform a reset 23 | top->clk = 0; 24 | top->eval(); 25 | top->reset_n = 0; 26 | top->clk = 1; 27 | top->eval(); 28 | top->reset_n = 1; 29 | 30 | SDL_Init(SDL_INIT_VIDEO); 31 | 32 | SDL_Window* window = 33 | SDL_CreateWindow( 34 | "Framebuffer Verilator", 35 | SDL_WINDOWPOS_UNDEFINED, 36 | SDL_WINDOWPOS_UNDEFINED, 37 | WINDOW_WIDTH, 38 | WINDOW_HEIGHT, 39 | 0 40 | ); 41 | 42 | SDL_Renderer* renderer = 43 | SDL_CreateRenderer( 44 | window, 45 | -1, 46 | SDL_RENDERER_ACCELERATED 47 | ); 48 | 49 | SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); 50 | SDL_RenderClear(renderer); 51 | 52 | SDL_Event e; 53 | 54 | SDL_Texture* texture = 55 | SDL_CreateTexture( 56 | renderer, 57 | SDL_PIXELFORMAT_ARGB8888, 58 | SDL_TEXTUREACCESS_STREAMING, 59 | WINDOW_WIDTH, 60 | WINDOW_HEIGHT 61 | ); 62 | 63 | bool quit = false; 64 | 65 | int hnum = 0; 66 | int vnum = 0; 67 | 68 | while (!quit) { 69 | 70 | while (SDL_PollEvent(&e) == 1) { 71 | if (e.type == SDL_QUIT) { 72 | quit = true; 73 | } else if (e.type == SDL_KEYDOWN) { 74 | switch (e.key.keysym.sym) { 75 | case SDLK_q: 76 | quit = true; 77 | default: 78 | break; 79 | } 80 | } 81 | } 82 | 83 | auto keystate = SDL_GetKeyboardState(NULL); 84 | 85 | top->reset_n = !keystate[SDL_SCANCODE_ESCAPE]; 86 | 87 | top->but1 = keystate[SDL_SCANCODE_1]; 88 | top->but2 = keystate[SDL_SCANCODE_2]; 89 | top->but3 = keystate[SDL_SCANCODE_3]; 90 | 91 | // simulate for 20000 clocks 92 | for (int i = 0; i < 20000; ++i) { 93 | 94 | top->clk = 0; 95 | top->eval(); 96 | top->clk = 1; 97 | top->eval(); 98 | 99 | // h and v blank logic 100 | if ((0 == top->hsync) && (0 == top->vsync)) { 101 | hnum = -128; 102 | vnum = -28; 103 | } 104 | 105 | // active frame 106 | if ((hnum >= 0) && (hnum < 640) && (vnum >= 0) && (vnum < 480)) { 107 | framebuffer.at((vnum * WINDOW_WIDTH + hnum) * 4 + 0) = (top->rrggbb & 0b000011) >> 0 << 6; 108 | framebuffer.at((vnum * WINDOW_WIDTH + hnum) * 4 + 1) = (top->rrggbb & 0b001100) >> 2 << 6; 109 | framebuffer.at((vnum * WINDOW_WIDTH + hnum) * 4 + 2) = (top->rrggbb & 0b110000) >> 4 << 6; 110 | } 111 | 112 | // keep track of encountered fields 113 | hnum++; 114 | if (hnum >= 640 + 24 + 40) { 115 | hnum = -128; 116 | vnum++; 117 | } 118 | 119 | if (vnum >= 480 + 9 + 3) { 120 | vnum = -28; 121 | } 122 | } 123 | 124 | SDL_UpdateTexture( 125 | texture, 126 | NULL, 127 | framebuffer.data(), 128 | WINDOW_WIDTH * 4 129 | ); 130 | 131 | SDL_RenderCopy( 132 | renderer, 133 | texture, 134 | NULL, 135 | NULL 136 | ); 137 | 138 | SDL_RenderPresent(renderer); 139 | } 140 | 141 | top->final(); 142 | delete top; 143 | 144 | SDL_DestroyRenderer(renderer); 145 | SDL_DestroyWindow(window); 146 | SDL_Quit(); 147 | 148 | return EXIT_SUCCESS; 149 | } 150 | --------------------------------------------------------------------------------