├── .gitignore ├── LICENSE ├── README.md ├── blocking └── blocking.v ├── build.cmd ├── build.ps1 ├── build.sh ├── byte_adder ├── byte_adder.pdf ├── byte_adder.v ├── full_adder.v └── half_adder.v ├── clk_divider ├── clk_divider.v ├── clk_pll.ppf ├── clk_pll.qip ├── clk_pll.v ├── clk_pll_inst.v ├── tb_clk_divider.v ├── tb_clk_pll.v └── top.v ├── counter ├── counter.v └── tb_counter.v ├── dff ├── dff.v └── tb_dff.v ├── digital_tube ├── digital_tube.csv ├── digital_tube_data.v ├── digital_tube_display.v ├── tb_top.v └── top.v ├── digital_tube_dynamic ├── digital_tube_data.v ├── digital_tube_display.v ├── digital_tube_dynamic.csv └── top.v ├── fifo ├── scfifo.v └── tb_scfifo.v ├── fsm ├── digital_tube_data.v ├── digital_tube_display.v ├── fsm.v ├── key_filter.v ├── tb_fsm.v └── top.v ├── full_adder ├── full_adder.pdf ├── full_adder.svg ├── full_adder.v ├── full_adder_tb.v └── half_adder.v ├── gate └── gate.v ├── half_adder ├── half_adder.svg ├── half_adder.v └── half_adder_tb.v ├── hdmi_bitmap_display ├── README.md ├── fifo_uart.qip ├── fifo_uart.v └── fifo_uart_inst.v ├── hdmi_display ├── README.md ├── char-buffer.mif ├── clk_delay.v ├── ddio.bsf ├── ddio.ppf ├── ddio.qip ├── ddio.v ├── ddio_inst.v ├── encode.v ├── font.mif ├── hdmi_ctrl.v ├── hdmi_display.csv ├── index_color_to_rgb.v ├── par_to_ser.v ├── pixel_index_color.v ├── pixel_to_char.v ├── pll.inc ├── pll.ppf ├── pll.qip ├── pll.v ├── pll_inst.v ├── ram_buffer.bsf ├── ram_buffer.qip ├── ram_buffer.v ├── ram_buffer_bb.v ├── ram_buffer_inst.v ├── rom_font.bsf ├── rom_font.qip ├── rom_font.v ├── rom_font_bb.v ├── rom_font_inst.v ├── top.v └── vga_ctrl.v ├── key_filter ├── digital_tube_data.v ├── digital_tube_display.v ├── key_filter.csv ├── key_filter.v ├── tb_key_filter.v └── top.v ├── led └── led.v ├── ram_ip ├── init_data.mif ├── ram_buffer.qip ├── ram_buffer.v ├── ram_buffer_inst.v ├── tb_top.v └── top.v ├── resources ├── font │ ├── ascii-font.png │ ├── ascii-font.psd │ └── init-screen.txt └── script │ ├── gen_char_buffer.py │ ├── gen_font.py │ ├── gen_index_color_to_rgb.py │ └── mif.py ├── rs232 ├── rs232.csv ├── tb_top.v ├── tb_uart_rx.v ├── tb_uart_tx.v ├── top.v ├── uart_rx.v └── uart_tx.v ├── sdram ├── README.md ├── fifo_async_8bit.qip ├── fifo_async_8bit.v ├── fifo_async_8bit_inst.v ├── gen_addr.py ├── micron-256mb-sdr.pdf ├── mt48lc16m16a2.v ├── op.v ├── rx_fsm.v ├── sdr_pll.ppf ├── sdr_pll.qip ├── sdr_pll.v ├── sdr_pll_inst.v ├── sdram_ctrl.v ├── sdram_fsm.v ├── tb_rx_fsm.v ├── tb_sdram_ctrl.v ├── tb_tx_fsm.v ├── top.v ├── tx_fsm.v ├── uart_rx.v └── uart_tx.v ├── timer ├── convert.v ├── counter.v ├── digital_tube_data.v ├── digital_tube_display.v ├── timer.csv └── top.v ├── vga_ctrl ├── pll_vga.ppf ├── pll_vga.qip ├── pll_vga.v ├── pll_vga_inst.v ├── tb_top.v ├── tb_vga_ctrl.v ├── top.v ├── vga_ctrl.csv ├── vga_ctrl.v └── vga_data.v ├── vga_display ├── README.md ├── char-buffer.mif ├── clk_delay.v ├── font.mif ├── index_color_to_rgb.v ├── pixel_index_color.v ├── pixel_to_char.v ├── pll_vga.ppf ├── pll_vga.qip ├── pll_vga.v ├── pll_vga_inst.v ├── ram_buffer.qip ├── ram_buffer.v ├── ram_buffer_inst.v ├── rom_font.qip ├── rom_font.v ├── rom_font_inst.v ├── tb_pixel_to_char.v ├── tb_top.v ├── tb_vga_ctrl.v ├── top.v ├── vga_ctrl.v └── vga_display.csv └── water_led └── water_led.v /.gitignore: -------------------------------------------------------------------------------- 1 | # hidden files: 2 | 3 | .* 4 | 5 | !.gitignore 6 | 7 | # Prerequisites 8 | *.d 9 | *.vcd 10 | 11 | # Compiled Object files 12 | *.slo 13 | *.lo 14 | *.o 15 | *.obj 16 | *.pyc 17 | *.pyo 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Compiled Dynamic libraries 24 | *.so 25 | *.dylib 26 | *.dll 27 | 28 | # Fortran module files 29 | *.mod 30 | *.smod 31 | 32 | # Compiled Static libraries 33 | *.lai 34 | *.la 35 | *.a 36 | *.lib 37 | 38 | # Executables 39 | *.exe 40 | *.out 41 | *.app 42 | 43 | # vscode ignore 44 | 45 | .vscode/* 46 | !.vscode/settings.json 47 | !.vscode/tasks.json 48 | !.vscode/launch.json 49 | !.vscode/extensions.json 50 | *.code-workspace 51 | 52 | # Local History for Visual Studio Code 53 | .history/ 54 | 55 | # ignore quartus files ######################################################## 56 | 57 | *.qpf 58 | *.qsf 59 | *.bak 60 | *.qws 61 | *.rpt 62 | db 63 | incremental_db 64 | output_files 65 | simulation 66 | greybox_tmp 67 | 68 | # Vim.gitignore ############################################################### 69 | 70 | [._]*.s[a-w][a-z] 71 | [._]s[a-w][a-z] 72 | *.un~ 73 | Session.vim 74 | .netrwhist 75 | *~ 76 | 77 | # Emacs.gitignore ############################################################# 78 | 79 | # -*- mode: gitignore; -*- 80 | *~ 81 | \#*\# 82 | /.emacs.desktop 83 | /.emacs.desktop.lock 84 | *.elc 85 | auto-save-list 86 | tramp 87 | .\#* 88 | 89 | # Org-mode 90 | .org-id-locations 91 | *_archive 92 | 93 | # flymake-mode 94 | *_flymake.* 95 | 96 | # eshell files 97 | /eshell/history 98 | /eshell/lastdir 99 | 100 | # elpa packages 101 | /elpa/ 102 | 103 | # reftex files 104 | *.rel 105 | 106 | # AUCTeX auto folder 107 | /auto/ 108 | 109 | # cask packages 110 | .cask/ 111 | 112 | 113 | # OSX.gitignore ############################################################### 114 | 115 | .DS_Store 116 | .AppleDouble 117 | .LSOverride 118 | 119 | # Icon must end with two \r 120 | Icon 121 | 122 | # Thumbnails 123 | ._* 124 | 125 | # Files that might appear in the root of a volume 126 | .DocumentRevisions-V100 127 | .fseventsd 128 | .Spotlight-V100 129 | .TemporaryItems 130 | .Trashes 131 | .VolumeIcon.icns 132 | 133 | # Directories potentially created on remote AFP share 134 | .AppleDB 135 | .AppleDesktop 136 | Network Trash Folder 137 | Temporary Items 138 | .apdisk 139 | 140 | # Windows.gitignore ########################################################### 141 | 142 | # Windows image file caches 143 | Thumbs.db 144 | ehthumbs.db 145 | 146 | # Folder config file 147 | Desktop.ini 148 | 149 | # Recycle Bin used on file shares 150 | $RECYCLE.BIN/ 151 | 152 | # Windows Installer files 153 | *.cab 154 | *.msi 155 | *.msm 156 | *.msp 157 | 158 | # Windows shortcuts 159 | *.lnk 160 | 161 | # Linux.gitignore ############################################################# 162 | 163 | *~ 164 | 165 | # KDE directory preferences 166 | .directory 167 | 168 | # Linux trash folder which might appear on any partition or disk 169 | .Trash-* 170 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # learn-verilog 2 | Learn Verilog 3 | -------------------------------------------------------------------------------- /blocking/blocking.v: -------------------------------------------------------------------------------- 1 | 2 | module blocking ( 3 | input a, 4 | input clk, 5 | output reg b, 6 | output reg c, 7 | output reg d 8 | ); 9 | 10 | // not recommended: 11 | always @ (posedge clk) begin 12 | d = c; 13 | c = b; 14 | b = a; 15 | end 16 | 17 | // recommended: 18 | // always @ (posedge clk) begin 19 | // d <= c; 20 | // c <= b; 21 | // b <= a; 22 | // end 23 | 24 | endmodule 25 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set pwd=%cd% 4 | echo set pwd = %pwd% 5 | 6 | set args=0 7 | for %%x in (%*) do ( 8 | set /A args+=1 9 | ) 10 | 11 | if %args% Geq 1 goto :SET_TOP_MODULE_BY_ARG 12 | 13 | for %%A in ("%pwd%") do ( 14 | set top_module=%%~nxA 15 | ) 16 | goto :SET_TOP_MODULE_OK 17 | 18 | :SET_TOP_MODULE_BY_ARG 19 | set top_module=%1 20 | if "%top_module:~-2%" == ".v" ( 21 | set top_module=%top_module:~0,-2% 22 | ) 23 | 24 | :SET_TOP_MODULE_OK 25 | echo set top module = %top_module% 26 | 27 | set src_file=%top_module%.v 28 | set src_out_file=%top_module%.out 29 | set tb_file=tb_%top_module%.v 30 | set tb_out_file=tb_%top_module%.out 31 | set wave_out_file=tb_%top_module%.vcd 32 | 33 | if Not Exist %src_file% goto :ERROR_SRC_FILE 34 | 35 | echo compile %src_file% -^> %src_out_file% ... 36 | iverilog -y . -s %top_module% -o %src_out_file% %src_file% 37 | if ERRORLEVEL 1 goto :END 38 | 39 | If Not Exist %tb_file% goto :NO_TESTBENCH 40 | 41 | echo compile %tb_file% -^> %tb_out_file% ... 42 | iverilog -y . -s tb_%top_module% -o %tb_out_file% %src_file% %tb_file% 43 | if ERRORLEVEL 1 goto :END 44 | 45 | echo simulate %tb_out_file ... 46 | vvp %tb_out_file% 47 | if ERRORLEVEL 1 goto :END 48 | 49 | echo open gtkwave for %wave_out_file% ... 50 | start gtkwave %wave_out_file% 51 | 52 | goto :END 53 | 54 | :NO_TESTBENCH 55 | echo [WARNING] testbench file %tb_file% not found. 56 | goto :END 57 | 58 | :ERROR_SRC_FILE 59 | echo source file %src_file% not found. 60 | goto :END 61 | 62 | :END 63 | -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | # This script is used to build the project using PowerShell: 2 | 3 | function Get-ProjectName { 4 | $currentPath = $pwd.Path 5 | $lastDirName = $currentPath.Split('\')[-1] 6 | return $lastDirName 7 | } 8 | 9 | function Is-FileExist { 10 | param ( 11 | [string]$fileName 12 | ) 13 | $filePath = Join-Path $pwd.Path $fileName 14 | return Test-Path $filePath 15 | } 16 | 17 | # 返回当前工程的top文件,依次查找: 18 | # 1. 传入的参数 19 | # 2. 与当前目录名同名的.v文件 20 | # 3. top.v文件 21 | function Get-ProjectTopName { 22 | param( 23 | [string] $name 24 | ) 25 | if ($name.Length -gt 0) { 26 | $top = $name 27 | if ($top.EndsWith(".v")) { 28 | $top = $top.Substring(0, $top.Length - 2) 29 | } 30 | if (Is-FileExist "$top.v") { 31 | return $top 32 | } 33 | Write-Error "Cannot find file: $top.v" 34 | exit 1 35 | } 36 | $top = Get-ProjectName 37 | if (Is-FileExist "$top.v") { 38 | return $top 39 | } 40 | $top = "top" 41 | if (Is-FileExist "$top.v") { 42 | return $top 43 | } 44 | Write-Error "Cannot determin the .v file." 45 | exit 1 46 | } 47 | 48 | function Get-Testbench { 49 | param ( 50 | [string]$name 51 | ) 52 | $module_tb = "${name}_tb" 53 | if (Is-FileExist "$module_tb.v") { 54 | return $module_tb 55 | } 56 | return "" 57 | } 58 | 59 | # 允许一个参数指定module: 60 | if ($args.Count -gt 1) { 61 | Write-Error "Too many arguments. Only one argument is allowed." 62 | exit 1 63 | } 64 | $arg0 = "" 65 | if ($args.Count -gt 0) { 66 | $arg0 = $args[0] 67 | } 68 | 69 | $workingDir = $pwd.Path 70 | echo "set pwd = $workingDir" 71 | 72 | $module = Get-ProjectTopName($arg0) 73 | echo "set top module = $module" 74 | 75 | echo "compile $module.v..." 76 | iverilog -g2005 -y . -s $module -o "$module.out" "$module.v" 77 | if ($LASTEXITCODE -ne 0) { 78 | exit $LASTEXITCODE 79 | } 80 | 81 | # 自动检测testbench模块,如果存在则编译并运行: 82 | $module_tb = Get-Testbench($module) 83 | if ($module_tb.Length -eq 0) { 84 | echo "no test bench found. skip test." 85 | } else { 86 | echo "compile test bench module: ${module_tb}.v..." 87 | iverilog -g2005 -y . -s ${module_tb} -o "${module_tb}.out" "${module_tb}.v" 88 | if ($LASTEXITCODE -ne 0) { 89 | exit $LASTEXITCODE 90 | } 91 | echo "simulate ${module_tb}.out..." 92 | if (Is-FileExist "test.vcd") { 93 | rm test.vcd 94 | } 95 | vvp "${module_tb}.out" 96 | if ($LASTEXITCODE -ne 0) { 97 | exit $LASTEXITCODE 98 | } 99 | echo "open gtkwave for ${module_tb}..." 100 | start gtkwave test.vcd 101 | } 102 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "set pwd = $(pwd)" 3 | 4 | top_module=`pwd | awk -F/ '{print $NF}'` 5 | 6 | if ! [ -z "$1" ]; then 7 | top_module="$1" 8 | top_module=${top_module%.v} 9 | fi 10 | 11 | src_file="$top_module.v" 12 | src_out_file="$top_module.out" 13 | tb_file="tb_$top_module.v" 14 | tb_out_file="tb_$top_module.out" 15 | wave_out_file="tb_$top_module.vcd" 16 | 17 | echo "set top module = $top_module" 18 | 19 | if ! [ -e $src_file ]; then 20 | echo "source file $src_file not found." 21 | exit 1 22 | fi 23 | 24 | echo "compile $src_file -> $src_out_file ..." 25 | iverilog -y . -s $top_module -o $src_out_file $src_file 26 | if ! [ $? -eq 0 ]; then 27 | exit 1 28 | fi 29 | 30 | if ! [ -e $tb_file ]; then 31 | echo "[WARNING] testbench file $tb_file not found." 32 | else 33 | echo "compile $tb_file -> $tb_out_file ..." 34 | iverilog -y . -s tb_$top_module -o $tb_out_file $src_file $tb_file 35 | if ! [ $? -eq 0 ]; then 36 | exit 1 37 | fi 38 | 39 | echo "simulate $tb_out_file ..." 40 | vvp $tb_out_file 41 | if ! [ $? -eq 0 ]; then 42 | exit 1 43 | fi 44 | 45 | echo "open gtkwave for $wave_out_file ..." 46 | gtkwave $wave_out_file 47 | fi 48 | -------------------------------------------------------------------------------- /byte_adder/byte_adder.v: -------------------------------------------------------------------------------- 1 | `include "full_adder.v" 2 | 3 | module byte_adder ( 4 | input [7:0] a, 5 | input [7:0] b, 6 | input cin, 7 | output carry, 8 | output [7:0] sum 9 | ); 10 | 11 | wire c7; 12 | wire c6; 13 | wire c5; 14 | wire c4; 15 | wire c3; 16 | wire c2; 17 | wire c1; 18 | 19 | full_adder f0( 20 | .a(a[0]), 21 | .b(b[0]), 22 | .cin(cin), 23 | .carry(c1), 24 | .sum(sum[0]) 25 | ); 26 | 27 | full_adder f1( 28 | .a(a[1]), 29 | .b(b[1]), 30 | .cin(c1), 31 | .carry(c2), 32 | .sum(sum[1]) 33 | ); 34 | 35 | full_adder f2( 36 | .a(a[2]), 37 | .b(b[2]), 38 | .cin(c2), 39 | .carry(c3), 40 | .sum(sum[2]) 41 | ); 42 | 43 | full_adder f3( 44 | .a(a[3]), 45 | .b(b[3]), 46 | .cin(c3), 47 | .carry(c4), 48 | .sum(sum[3]) 49 | ); 50 | 51 | full_adder f4( 52 | .a(a[4]), 53 | .b(b[4]), 54 | .cin(c4), 55 | .carry(c5), 56 | .sum(sum[4]) 57 | ); 58 | 59 | full_adder f5( 60 | .a(a[5]), 61 | .b(b[5]), 62 | .cin(c5), 63 | .carry(c6), 64 | .sum(sum[5]) 65 | ); 66 | 67 | full_adder f6( 68 | .a(a[6]), 69 | .b(b[6]), 70 | .cin(c6), 71 | .carry(c7), 72 | .sum(sum[6]) 73 | ); 74 | 75 | full_adder f7( 76 | .a(a[7]), 77 | .b(b[7]), 78 | .cin(c7), 79 | .carry(carry), 80 | .sum(sum[7]) 81 | ); 82 | 83 | endmodule 84 | -------------------------------------------------------------------------------- /byte_adder/full_adder.v: -------------------------------------------------------------------------------- 1 | `include "half_adder.v" 2 | 3 | module full_adder( 4 | input a, 5 | input b, 6 | input cin, 7 | output carry, 8 | output sum 9 | ); 10 | 11 | wire t_carry1; 12 | wire t_carry2; 13 | wire t_sum; 14 | 15 | half_adder h1( 16 | .a(a), 17 | .b(b), 18 | .carry(t_carry1), 19 | .sum(t_sum) 20 | ); 21 | 22 | half_adder h2( 23 | .a(t_sum), 24 | .b(cin), 25 | .carry(t_carry2), 26 | .sum(sum) 27 | ); 28 | 29 | assign carry = t_carry1 | t_carry2; 30 | 31 | endmodule 32 | -------------------------------------------------------------------------------- /byte_adder/half_adder.v: -------------------------------------------------------------------------------- 1 | /* 2 | Half Adder: 3 | 4 | a b carry sum 5 | --------------- 6 | 0 + 0 = 0 0 7 | 0 + 1 = 0 1 8 | 1 + 0 = 0 1 9 | 1 + 1 = 1 0 10 | 11 | */ 12 | 13 | module half_adder( 14 | input a, 15 | input b, 16 | output carry, 17 | output sum 18 | ); 19 | assign carry = a & b; 20 | assign sum = a ^ b; 21 | endmodule 22 | -------------------------------------------------------------------------------- /clk_divider/clk_divider.v: -------------------------------------------------------------------------------- 1 | 2 | module clk_divider ( 3 | input clk, 4 | input rst, 5 | output clk2, 6 | output clk4, 7 | output clk8 8 | ); 9 | 10 | reg [3:0] cnt; 11 | 12 | always @ (posedge clk) begin 13 | if (rst == 1'b1) 14 | cnt <= 4'b0; 15 | else 16 | cnt <= cnt + 1'b1; 17 | end 18 | 19 | assign clk2 = ~cnt[1]; 20 | assign clk4 = ~cnt[2]; 21 | assign clk8 = cnt[3]; 22 | 23 | endmodule 24 | -------------------------------------------------------------------------------- /clk_divider/clk_pll.ppf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /clk_divider/clk_pll.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "ALTPLL" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "clk_pll.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "clk_pll_inst.v"] 6 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "clk_pll.ppf"] 7 | -------------------------------------------------------------------------------- /clk_divider/clk_pll_inst.v: -------------------------------------------------------------------------------- 1 | clk_pll clk_pll_inst ( 2 | .areset ( areset_sig ), 3 | .inclk0 ( inclk0_sig ), 4 | .c0 ( c0_sig ), 5 | .locked ( locked_sig ) 6 | ); 7 | -------------------------------------------------------------------------------- /clk_divider/tb_clk_divider.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module tb_clk_divider (); 4 | 5 | reg clk; 6 | reg rst; 7 | wire clk2; 8 | wire clk4; 9 | wire clk8; 10 | 11 | initial begin 12 | clk = 1'b1; 13 | rst = 1'b1; 14 | #100 15 | rst = 1'b0; 16 | end 17 | 18 | always #10 clk = ~clk; 19 | 20 | clk_divider ins( 21 | .clk(clk), 22 | .rst(rst), 23 | .clk2(clk2), 24 | .clk4(clk4), 25 | .clk8(clk8) 26 | ); 27 | 28 | endmodule 29 | -------------------------------------------------------------------------------- /clk_divider/tb_clk_pll.v: -------------------------------------------------------------------------------- 1 | `timescale 1ps/1ps 2 | 3 | module tb_clk_pll (); 4 | 5 | reg clk; 6 | reg rst_n; 7 | 8 | wire pll_clk; 9 | wire locked; 10 | 11 | clk_pll clk_pll_inst ( 12 | .areset ( ~rst_n ), 13 | .inclk0 ( clk ), 14 | .c0 ( pll_clk ), 15 | .locked ( locked ) 16 | ); 17 | 18 | initial begin 19 | clk = 1'b1; 20 | rst_n = 1'b0; 21 | #10 22 | rst_n = 1'b1; 23 | #5000 24 | $finish; 25 | end 26 | 27 | always #1 clk = ~clk; 28 | 29 | endmodule 30 | -------------------------------------------------------------------------------- /clk_divider/top.v: -------------------------------------------------------------------------------- 1 | module top( 2 | input wire clk, 3 | input wire rst_n, 4 | output wire pll_clk, 5 | output wire locked 6 | ); 7 | 8 | clk_pll clk_pll_inst ( 9 | .areset ( ~rst_n ), 10 | .inclk0 ( clk ), 11 | .c0 ( pll_clk ), 12 | .locked ( locked ) 13 | ); 14 | 15 | endmodule 16 | -------------------------------------------------------------------------------- /counter/counter.v: -------------------------------------------------------------------------------- 1 | // counter from 0x000000 ~ 0xffffff 2 | 3 | module counter 4 | #( 5 | parameter CNT_MAX = 'h1000000, // 0 ~ 0xffffff 6 | parameter SYS_CLK = 'd50_000_000 // default to 50MHz 7 | ) 8 | ( 9 | input clk, 10 | input rst_n, 11 | output reg [23:0] cnt 12 | ); 13 | 14 | reg [31:0] inc; 15 | 16 | always @ (posedge clk or negedge rst_n) begin 17 | if (! rst_n) begin 18 | cnt <= 24'b0; 19 | inc <= 32'b0; 20 | end else begin 21 | if (inc == (SYS_CLK - 1)) begin 22 | inc <= 32'b0; 23 | if (cnt == (CNT_MAX -1)) 24 | cnt <= 24'b0; 25 | else 26 | cnt <= cnt + 1; 27 | end else begin 28 | inc <= inc + 1; 29 | end 30 | end 31 | end 32 | 33 | endmodule 34 | -------------------------------------------------------------------------------- /counter/tb_counter.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module tb_counter (); 4 | 5 | reg clk; 6 | reg rst_n; 7 | wire [23:0] cnt; 8 | 9 | counter #(10, 50) component( 10 | .clk (clk), 11 | .rst_n (rst_n), 12 | .cnt (cnt) 13 | ); 14 | 15 | initial begin 16 | clk = 1'b1; 17 | rst_n = 1'b0; 18 | #10 19 | rst_n = 1'b1; 20 | #20000 21 | $finish; 22 | end 23 | 24 | always #10 clk = ~clk; 25 | 26 | initial begin 27 | $dumpfile("tb_counter.vcd"); 28 | $dumpvars(0, component); 29 | end 30 | 31 | endmodule 32 | -------------------------------------------------------------------------------- /dff/dff.v: -------------------------------------------------------------------------------- 1 | 2 | module dff( 3 | input clk, 4 | input rst_n, 5 | input d, 6 | output reg out 7 | ); 8 | 9 | // async reset: 10 | always @ (posedge clk or negedge rst_n) begin 11 | if (rst_n == 1'b0) 12 | out <= 0; 13 | else 14 | out <= d; 15 | end 16 | 17 | endmodule 18 | -------------------------------------------------------------------------------- /dff/tb_dff.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module tb_dff (); 4 | 5 | reg clk; 6 | reg rst_n; 7 | reg d; 8 | wire out; 9 | 10 | dff dff_instance( 11 | .clk(clk), 12 | .rst_n(rst_n), 13 | .d(d), 14 | .out(out) 15 | ); 16 | 17 | initial begin 18 | clk = 1'b1; 19 | rst_n = 1'b0; 20 | d = 1'b0; 21 | #50 22 | rst_n = 1'b1; 23 | #500 24 | $finish; 25 | end 26 | 27 | always #10 begin 28 | clk = ~clk; 29 | end 30 | 31 | always #20 begin 32 | #5 d = ~d; 33 | end 34 | 35 | initial begin 36 | $dumpfile("tb_dff.vcd"); 37 | $dumpvars(0, dff_instance); 38 | end 39 | 40 | endmodule 41 | -------------------------------------------------------------------------------- /digital_tube/digital_tube.csv: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Intel Corporation. All rights reserved. 2 | # Your use of Intel Corporation's design tools, logic functions 3 | # and other software and tools, and any partner logic 4 | # functions, and any output files from any of the foregoing 5 | # (including device programming or simulation files), and any 6 | # associated documentation or information are expressly subject 7 | # to the terms and conditions of the Intel Program License 8 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 9 | # the Intel FPGA IP License Agreement, or other applicable license 10 | # agreement, including, without limitation, that your use is for 11 | # the sole purpose of programming logic devices manufactured by 12 | # Intel and sold by Intel or its authorized distributors. Please 13 | # refer to the applicable agreement for further details, at 14 | # https://fpgasoftware.intel.com/eula. 15 | 16 | # Quartus Prime Version 20.1.1 Build 720 11/11/2020 SJ Lite Edition 17 | # File: C:\Users\Michael\Git\GitHub\learn-verilog\digital_tube\digital_tube.csv 18 | # Generated on: Wed Oct 26 17:45:24 2022 19 | 20 | # Note: The column header names should not be changed if you wish to import this .csv file into the Quartus Prime software. 21 | 22 | To,Direction,Location,I/O Bank,VREF Group,Fitter Location,I/O Standard,Reserved,Current Strength,Slew Rate,Differential Pair,Strict Preservation 23 | clk,Input,PIN_E1,1,B1_N0,PIN_E1,2.5 V,,,,, 24 | ds,Output,PIN_R1,2,B2_N0,PIN_R1,2.5 V,,,,, 25 | oe,Output,PIN_L11,4,B4_N0,PIN_L11,2.5 V,,,,, 26 | rst_n,Input,PIN_M15,5,B5_N0,PIN_M15,2.5 V,,,,, 27 | shcp,Output,PIN_B1,1,B1_N0,PIN_B1,2.5 V,,,,, 28 | stcp,Output,PIN_K9,4,B4_N0,PIN_K9,2.5 V,,,,, 29 | -------------------------------------------------------------------------------- /digital_tube/digital_tube_data.v: -------------------------------------------------------------------------------- 1 | // 6位数码管输入数据 2 | 3 | module digital_tube_data 4 | ( 5 | input clk, 6 | input rst_n, 7 | input [47:0] data, // 输入数据 8 x 6 = 48 bit 8 | output reg [7:0] seg, 9 | output reg [5:0] sel 10 | ); 11 | 12 | reg [15:0] cnt16; // 0 ~ 65535 13 | 14 | always @ (posedge clk or negedge rst_n) begin 15 | if (! rst_n) begin 16 | cnt16 <= 16'b0; 17 | seg <= 8'b0000_0000; 18 | sel <= 6'b000_001; 19 | end else begin 20 | cnt16 <= cnt16 + 16'b1; 21 | if (cnt16 == 16'hffff) begin 22 | case (sel) 23 | 6'b000_001: begin 24 | sel <= 6'b000_010; 25 | seg <= data[15:8]; 26 | end 27 | 6'b000_010: begin 28 | sel <= 6'b000_100; 29 | seg <= data[23:16]; 30 | end 31 | 6'b000_100: begin 32 | sel <= 6'b001_000; 33 | seg <= data[31:24]; 34 | end 35 | 6'b001_000: begin 36 | sel <= 6'b010_000; 37 | seg <= data[39:32]; 38 | end 39 | 6'b010_000: begin 40 | sel <= 6'b100_000; 41 | seg <= data[47:40]; 42 | end 43 | 6'b100_000: begin 44 | sel <= 6'b000_001; 45 | seg <= data[7:0]; 46 | end 47 | default: begin 48 | sel <= 6'b000_001; 49 | seg <= data[7:0]; 50 | end 51 | endcase 52 | end 53 | end 54 | end 55 | 56 | endmodule 57 | -------------------------------------------------------------------------------- /digital_tube/digital_tube_display.v: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | Digital Tube Display 数码管动态显示 4 | 5 | 位选信号 a ~ h: 0点亮 6 | 7 | ┌───────────────┐ 8 | │ a │ 9 | ├───┬───────┬───┤ 10 | │ │ │ │ 11 | │ f │ │ b │ 12 | │ │ │ │ 13 | ├───┴───────┴───┤ 14 | │ g │ 15 | ├───┬───────┬───┤ 16 | │ │ │ │ 17 | │ e │ │ c │ 18 | │ │ │ │ 19 | ├───┴───────┴───┤ ┌───┐ 20 | │ d │ │ h │ 21 | └───────────────┘ └───┘ 22 | 23 | ******************************************************************************/ 24 | 25 | module digital_tube_display 26 | ( 27 | input clk, 28 | input rst_n, 29 | input [7:0] seg, // 数码管位选信号 30 | input [5:0] sel, // 数码管段选信号 31 | output reg shcp, // 移位寄存器时钟 32 | output reg stcp, // 存储寄存器时钟 33 | output reg ds, // 串行数据输出至 74HC595 芯片 34 | output oe // 始能信号 =0 有效 35 | ); 36 | 37 | reg [1:0] cnt; 38 | reg [3:0] cnt_bit; 39 | 40 | wire [15:0] data; 41 | 42 | assign data = {seg[7:0], sel[5:0]}; 43 | 44 | always @ (posedge clk) begin 45 | if (! rst_n) begin 46 | cnt <= 2'b0; 47 | cnt_bit <= 4'b0; 48 | ds <= 1'b0; 49 | shcp <= 1'b0; 50 | stcp <= 1'b0; 51 | end else begin 52 | cnt <= cnt + 2'h1; 53 | 54 | if (cnt == 2'h3) begin 55 | if (cnt_bit == 4'hd) 56 | cnt_bit <= 4'h0; 57 | else 58 | cnt_bit <= cnt_bit + 4'h1; 59 | end else 60 | cnt_bit <= cnt_bit; 61 | 62 | // output ds: 63 | if (cnt == 2'b0) 64 | ds <= data[cnt_bit]; 65 | else 66 | ds <= ds; 67 | 68 | // output shcp: 69 | if (cnt == 2'h2) 70 | shcp <= 1'b1; 71 | else if (cnt == 2'h0) 72 | shcp <= 1'b0; 73 | else 74 | shcp <= shcp; 75 | 76 | // output stcp: 77 | if (cnt == 2'h0 && cnt_bit == 4'h0) 78 | stcp <= 1'b1; 79 | else if (cnt == 2'h2 && cnt_bit == 4'h0) 80 | stcp <= 1'b0; 81 | else 82 | stcp <= stcp; 83 | end 84 | end 85 | 86 | assign oe = 1'b0; 87 | 88 | endmodule 89 | -------------------------------------------------------------------------------- /digital_tube/tb_top.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module tb_top(); 4 | 5 | reg clk; 6 | reg rst_n; 7 | wire shcp; 8 | wire stcp; 9 | wire ds; 10 | wire oe; 11 | 12 | initial begin 13 | clk = 1'b1; 14 | rst_n = 1'b0; 15 | #100 16 | rst_n = 1'b1; 17 | #10000 18 | $finish; 19 | end 20 | 21 | always #10 clk = ~clk; 22 | 23 | top component( 24 | .clk (clk), 25 | .rst_n (rst_n), 26 | .shcp (shcp), 27 | .stcp (stcp), 28 | .ds (ds), 29 | .oe (oe) 30 | ); 31 | 32 | initial begin 33 | $dumpfile("tb_top.vcd"); 34 | $dumpvars(0, component); 35 | end 36 | 37 | endmodule 38 | -------------------------------------------------------------------------------- /digital_tube/top.v: -------------------------------------------------------------------------------- 1 | // display "SCHOOL" 2 | 3 | module top 4 | ( 5 | input clk, 6 | input rst_n, 7 | output shcp, 8 | output stcp, 9 | output ds, 10 | output oe 11 | ); 12 | 13 | localparam 14 | C = 8'b01100011, 15 | E = 8'b01100001, 16 | F = 8'b01110001, 17 | H = 8'b10010001, 18 | L = 8'b11100011, 19 | O = 8'b00000011, 20 | P = 8'b00110001, 21 | S = 8'b01001001, 22 | U = 8'b10000011; 23 | 24 | wire [7:0] seg; 25 | wire [5:0] sel; 26 | 27 | digital_tube_data digital_tube_data_inst ( 28 | .clk (clk), 29 | .rst_n (rst_n), 30 | .data ({ S, C, H, O, O, L }), 31 | .seg (seg), 32 | .sel (sel) 33 | ); 34 | 35 | digital_tube_display digital_tube_display_inst ( 36 | .clk (clk), 37 | .rst_n (rst_n), 38 | .seg (seg), 39 | .sel (sel), 40 | .shcp (shcp), 41 | .stcp (stcp), 42 | .ds (ds), 43 | .oe (oe) 44 | ); 45 | 46 | endmodule 47 | -------------------------------------------------------------------------------- /digital_tube_dynamic/digital_tube_data.v: -------------------------------------------------------------------------------- 1 | // 6位数码管输入数据 2 | 3 | module digital_tube_data 4 | ( 5 | input clk, 6 | input rst_n, 7 | input [47:0] data, // 输入数据 8 x 6 = 48 bit 8 | output reg [7:0] seg, 9 | output reg [5:0] sel 10 | ); 11 | 12 | reg [15:0] cnt16; // 0 ~ 65535 13 | 14 | always @ (posedge clk or negedge rst_n) begin 15 | if (! rst_n) begin 16 | cnt16 <= 16'b0; 17 | seg <= 8'b0000_0000; 18 | sel <= 6'b000_001; 19 | end else begin 20 | cnt16 <= cnt16 + 16'b1; 21 | if (cnt16 == 16'hffff) begin 22 | case (sel) 23 | 6'b000_001: begin 24 | sel <= 6'b000_010; 25 | seg <= data[15:8]; 26 | end 27 | 6'b000_010: begin 28 | sel <= 6'b000_100; 29 | seg <= data[23:16]; 30 | end 31 | 6'b000_100: begin 32 | sel <= 6'b001_000; 33 | seg <= data[31:24]; 34 | end 35 | 6'b001_000: begin 36 | sel <= 6'b010_000; 37 | seg <= data[39:32]; 38 | end 39 | 6'b010_000: begin 40 | sel <= 6'b100_000; 41 | seg <= data[47:40]; 42 | end 43 | 6'b100_000: begin 44 | sel <= 6'b000_001; 45 | seg <= data[7:0]; 46 | end 47 | default: begin 48 | sel <= 6'b000_001; 49 | seg <= data[7:0]; 50 | end 51 | endcase 52 | end 53 | end 54 | end 55 | 56 | endmodule 57 | -------------------------------------------------------------------------------- /digital_tube_dynamic/digital_tube_display.v: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | Digital Tube Display 数码管动态显示 4 | 5 | 位选信号 a ~ h: 0点亮 6 | 7 | ┌───────────────┐ 8 | │ a │ 9 | ├───┬───────┬───┤ 10 | │ │ │ │ 11 | │ f │ │ b │ 12 | │ │ │ │ 13 | ├───┴───────┴───┤ 14 | │ g │ 15 | ├───┬───────┬───┤ 16 | │ │ │ │ 17 | │ e │ │ c │ 18 | │ │ │ │ 19 | ├───┴───────┴───┤ ┌───┐ 20 | │ d │ │ h │ 21 | └───────────────┘ └───┘ 22 | 23 | ******************************************************************************/ 24 | 25 | module digital_tube_display 26 | ( 27 | input clk, 28 | input rst_n, 29 | input [7:0] seg, // 数码管位选信号 30 | input [5:0] sel, // 数码管段选信号 31 | output reg shcp, // 移位寄存器时钟 32 | output reg stcp, // 存储寄存器时钟 33 | output reg ds, // 串行数据输出至 74HC595 芯片 34 | output oe // 始能信号 =0 有效 35 | ); 36 | 37 | reg [1:0] cnt; 38 | reg [3:0] cnt_bit; 39 | 40 | wire [15:0] data; 41 | 42 | assign data = {seg[7:0], sel[5:0]}; 43 | 44 | always @ (posedge clk) begin 45 | if (! rst_n) begin 46 | cnt <= 2'b0; 47 | cnt_bit <= 4'b0; 48 | ds <= 1'b0; 49 | shcp <= 1'b0; 50 | stcp <= 1'b0; 51 | end else begin 52 | cnt <= cnt + 2'h1; 53 | 54 | if (cnt == 2'h3) begin 55 | if (cnt_bit == 4'hd) 56 | cnt_bit <= 4'h0; 57 | else 58 | cnt_bit <= cnt_bit + 4'h1; 59 | end else 60 | cnt_bit <= cnt_bit; 61 | 62 | // output ds: 63 | if (cnt == 2'b0) 64 | ds <= data[cnt_bit]; 65 | else 66 | ds <= ds; 67 | 68 | // output shcp: 69 | if (cnt == 2'h2) 70 | shcp <= 1'b1; 71 | else if (cnt == 2'h0) 72 | shcp <= 1'b0; 73 | else 74 | shcp <= shcp; 75 | 76 | // output stcp: 77 | if (cnt == 2'h0 && cnt_bit == 4'h0) 78 | stcp <= 1'b1; 79 | else if (cnt == 2'h2 && cnt_bit == 4'h0) 80 | stcp <= 1'b0; 81 | else 82 | stcp <= stcp; 83 | end 84 | end 85 | 86 | assign oe = 1'b0; 87 | 88 | endmodule 89 | -------------------------------------------------------------------------------- /digital_tube_dynamic/digital_tube_dynamic.csv: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Intel Corporation. All rights reserved. 2 | # Your use of Intel Corporation's design tools, logic functions 3 | # and other software and tools, and any partner logic 4 | # functions, and any output files from any of the foregoing 5 | # (including device programming or simulation files), and any 6 | # associated documentation or information are expressly subject 7 | # to the terms and conditions of the Intel Program License 8 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 9 | # the Intel FPGA IP License Agreement, or other applicable license 10 | # agreement, including, without limitation, that your use is for 11 | # the sole purpose of programming logic devices manufactured by 12 | # Intel and sold by Intel or its authorized distributors. Please 13 | # refer to the applicable agreement for further details, at 14 | # https://fpgasoftware.intel.com/eula. 15 | 16 | # Quartus Prime Version 20.1.1 Build 720 11/11/2020 SJ Lite Edition 17 | # File: C:\Users\Michael\Git\GitHub\learn-verilog\digital_tube_dynamic\digital_tube_dynamic.csv 18 | # Generated on: Wed Oct 26 18:45:32 2022 19 | 20 | # Note: The column header names should not be changed if you wish to import this .csv file into the Quartus Prime software. 21 | 22 | To,Direction,Location,I/O Bank,VREF Group,Fitter Location,I/O Standard,Reserved,Current Strength,Slew Rate,Differential Pair,Strict Preservation 23 | clk,Input,PIN_E1,1,B1_N0,PIN_E1,,,,,, 24 | ds,Output,PIN_R1,2,B2_N0,PIN_E7,,,,,, 25 | oe,Output,PIN_L11,4,B4_N0,PIN_R8,,,,,, 26 | rst_n,Input,PIN_M15,5,B5_N0,PIN_M2,,,,,, 27 | shcp,Output,PIN_B1,1,B1_N0,PIN_F1,,,,,, 28 | stcp,Output,PIN_K9,4,B4_N0,PIN_F2,,,,,, 29 | -------------------------------------------------------------------------------- /digital_tube_dynamic/top.v: -------------------------------------------------------------------------------- 1 | // display dynamic words 2 | 3 | module top 4 | ( 5 | input clk, 6 | input rst_n, 7 | output shcp, 8 | output stcp, 9 | output ds, 10 | output oe 11 | ); 12 | localparam 13 | C = 8'b01100011, 14 | E = 8'b01100001, 15 | F = 8'b01110001, 16 | H = 8'b10010001, 17 | L = 8'b11100011, 18 | O = 8'b00000011, 19 | P = 8'b00110001, 20 | U = 8'b10000011, 21 | X = 8'b11111111; 22 | 23 | reg [47:0] data; 24 | 25 | reg [25:0] cnt26; // 0 ~ 67108863 26 | 27 | wire [7:0] seg; 28 | wire [5:0] sel; 29 | 30 | digital_tube_data digital_tube_data_inst ( 31 | .clk (clk), 32 | .rst_n (rst_n), 33 | .data (data), 34 | .seg (seg), 35 | .sel (sel) 36 | ); 37 | 38 | digital_tube_display digital_tube_display_inst ( 39 | .clk (clk), 40 | .rst_n (rst_n), 41 | .seg (seg), 42 | .sel (sel), 43 | .shcp (shcp), 44 | .stcp (stcp), 45 | .ds (ds), 46 | .oe (oe) 47 | ); 48 | 49 | always @ (posedge clk or negedge rst_n) begin 50 | if (! rst_n) begin 51 | cnt26 <= 26'b0; 52 | end else begin 53 | cnt26 <= cnt26 + 26'b1; 54 | // 每隔约1秒更新数据: 55 | if (cnt26[25] == 1'b1) 56 | data <= { H, E, L, L, O, X }; 57 | else 58 | data <= { X, H, E, L, L, O }; 59 | end 60 | end 61 | 62 | endmodule 63 | -------------------------------------------------------------------------------- /fifo/scfifo.v: -------------------------------------------------------------------------------- 1 | // sync fifo 2 | 3 | module scfifo #( 4 | parameter DATA_BITS = 8, 5 | parameter SIZE = 8 // size must be 2, 4, 8, 16, ... 6 | ) 7 | ( 8 | input clk, 9 | input rst_n, 10 | input rdreq, 11 | input wrreq, 12 | input [DATA_BITS-1:0] data, 13 | output reg [DATA_BITS-1:0] q, 14 | output full, 15 | output empty 16 | ); 17 | 18 | localparam DEPTH_BITS = $clog2(SIZE); 19 | 20 | reg [DATA_BITS-1:0] mem [SIZE]; 21 | reg [DEPTH_BITS:0] rp; 22 | reg [DEPTH_BITS:0] wp; 23 | reg [DATA_BITS-1:0] q_cache; 24 | wire sig_empty; 25 | 26 | // write: 27 | always @ (posedge clk or negedge rst_n) begin 28 | if (! rst_n) begin 29 | wp <= 0; 30 | end else begin 31 | if (wrreq && !full) begin 32 | mem[wp[DEPTH_BITS-1:0]] <= data; 33 | wp <= wp + 1'b1; 34 | end 35 | end 36 | end 37 | 38 | // read: 39 | always @ (posedge clk or negedge rst_n) begin 40 | if (! rst_n) begin 41 | rp <= 0; 42 | end else begin 43 | if (rdreq && !empty) begin 44 | q_cache <= mem[rp[DEPTH_BITS-1:0]]; 45 | rp <= rp + 1'b1; 46 | end else begin 47 | q_cache <= {DATA_BITS{1'b0}}; 48 | end 49 | q <= q_cache; 50 | end 51 | end 52 | 53 | assign empty = (rp == wp) ? 1'b1 : 1'b0; 54 | assign full = rp[DEPTH_BITS] != wp[DEPTH_BITS] && (rp[DEPTH_BITS-1:0] == wp[DEPTH_BITS-1:0]); 55 | 56 | endmodule 57 | -------------------------------------------------------------------------------- /fifo/tb_scfifo.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | 3 | module tb_scfifo(); 4 | 5 | reg clk; 6 | reg rst_n; 7 | 8 | initial begin 9 | rst_n = 1'b0; 10 | #25 11 | rst_n = 1'b1; 12 | end 13 | 14 | // 50 MHz clk: 15 | initial begin 16 | clk = 1'b1; 17 | forever begin 18 | #10 clk = ~clk; 19 | end 20 | end 21 | 22 | reg rdreq; 23 | reg wrreq; 24 | reg [7:0] data; 25 | wire [7:0] q; 26 | wire empty; 27 | wire full; 28 | 29 | initial begin 30 | rdreq <= 1'b0; 31 | wrreq <= 1'b0; 32 | data <= 8'h00; 33 | #55 34 | // write 0xa1, 0xb2, 0xc3, 0xd4: 35 | wrreq <= 1'b1; 36 | data <= 8'ha1; 37 | #20 38 | wrreq <= 1'b1; 39 | data <= 8'hb2; 40 | #20 41 | wrreq <= 1'b1; 42 | data <= 8'hc3; 43 | #20 44 | wrreq <= 1'b1; 45 | data <= 8'hd4; 46 | #20 47 | // stop write and read 1: 48 | wrreq <= 1'b0; 49 | data <= 8'h00; 50 | rdreq <= 1'b1; 51 | #20 52 | // stop read: 53 | rdreq <= 1'b0; 54 | #20 55 | // write 5 bytes to full: 56 | wrreq <= 1'b1; 57 | data <= 8'h12; 58 | #20 59 | wrreq <= 1'b1; 60 | data <= 8'h34; 61 | #20 62 | wrreq <= 1'b1; 63 | data <= 8'h56; 64 | #20 65 | wrreq <= 1'b1; 66 | data <= 8'h78; 67 | #20 68 | wrreq <= 1'b1; 69 | data <= 8'h90; 70 | #20 71 | // stop write: 72 | wrreq <= 1'b0; 73 | data <= 8'h00; 74 | #20 75 | // read 9: 76 | rdreq <= 1'b1; 77 | #180 78 | // stop read: 79 | rdreq <= 1'b0; 80 | #20 81 | wrreq <= 1'b1; 82 | // write: 83 | data <= 8'hf1; 84 | #20 85 | data <= 8'hf2; 86 | #20 87 | data <= 8'hf3; 88 | #20 89 | data <= 8'hf4; 90 | #20 91 | data <= 8'hf5; 92 | #20 93 | data <= 8'hf6; 94 | #20 95 | data <= 8'hf7; 96 | #20 97 | data <= 8'hf8; 98 | #20 99 | data <= 8'hf9; 100 | #20 101 | wrreq <= 1'b0; 102 | rdreq <= 1'b1; 103 | #200 104 | // write: 105 | wrreq <= 1'b1; 106 | data <= 8'h11; 107 | #20 108 | // read and write: 109 | rdreq <= 1'b1; 110 | data <= 8'h22; 111 | #20 112 | rdreq <= 1'b1; 113 | data <= 8'h33; 114 | #20 115 | wrreq <= 1'b0; 116 | #20 117 | #20 118 | #20 119 | #20 120 | // read and write: 121 | wrreq <= 1'b1; 122 | rdreq <= 1'b1; 123 | data <= 8'h55; 124 | #20 125 | data <= 8'h66; 126 | #20 127 | wrreq <= 1'b0; 128 | #20 129 | #20 130 | rdreq <= 1'b0; 131 | #100; 132 | end 133 | 134 | scfifo component ( 135 | .clk (clk), 136 | .rst_n (rst_n), 137 | .rdreq (rdreq), 138 | .wrreq (wrreq), 139 | .data (data), 140 | .q (q), 141 | .empty (empty), 142 | .full (full) 143 | ); 144 | 145 | initial begin 146 | $dumpfile("tb_scfifo.vcd"); 147 | $dumpvars(0, component); 148 | #1500 149 | $finish; 150 | end 151 | 152 | endmodule 153 | -------------------------------------------------------------------------------- /fsm/digital_tube_data.v: -------------------------------------------------------------------------------- 1 | // 6位数码管输入数据 2 | 3 | module digital_tube_data 4 | ( 5 | input clk, 6 | input rst_n, 7 | input [47:0] data, // 输入数据 8 x 6 = 48 bit 8 | output reg [7:0] seg, 9 | output reg [5:0] sel 10 | ); 11 | 12 | reg [15:0] cnt16; // 0 ~ 65535 13 | 14 | always @ (posedge clk or negedge rst_n) begin 15 | if (! rst_n) begin 16 | cnt16 <= 16'b0; 17 | seg <= 8'b0000_0000; 18 | sel <= 6'b000_001; 19 | end else begin 20 | cnt16 <= cnt16 + 16'b1; 21 | if (cnt16 == 16'hffff) begin 22 | case (sel) 23 | 6'b000_001: begin 24 | sel <= 6'b000_010; 25 | seg <= data[15:8]; 26 | end 27 | 6'b000_010: begin 28 | sel <= 6'b000_100; 29 | seg <= data[23:16]; 30 | end 31 | 6'b000_100: begin 32 | sel <= 6'b001_000; 33 | seg <= data[31:24]; 34 | end 35 | 6'b001_000: begin 36 | sel <= 6'b010_000; 37 | seg <= data[39:32]; 38 | end 39 | 6'b010_000: begin 40 | sel <= 6'b100_000; 41 | seg <= data[47:40]; 42 | end 43 | 6'b100_000: begin 44 | sel <= 6'b000_001; 45 | seg <= data[7:0]; 46 | end 47 | default: begin 48 | sel <= 6'b000_001; 49 | seg <= data[7:0]; 50 | end 51 | endcase 52 | end 53 | end 54 | end 55 | 56 | endmodule 57 | -------------------------------------------------------------------------------- /fsm/digital_tube_display.v: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | Digital Tube Display 数码管动态显示 4 | 5 | 位选信号 a ~ h: 0点亮 6 | 7 | ┌───────────────┐ 8 | │ a │ 9 | ├───┬───────┬───┤ 10 | │ │ │ │ 11 | │ f │ │ b │ 12 | │ │ │ │ 13 | ├───┴───────┴───┤ 14 | │ g │ 15 | ├───┬───────┬───┤ 16 | │ │ │ │ 17 | │ e │ │ c │ 18 | │ │ │ │ 19 | ├───┴───────┴───┤ ┌───┐ 20 | │ d │ │ h │ 21 | └───────────────┘ └───┘ 22 | 23 | ******************************************************************************/ 24 | 25 | module digital_tube_display 26 | ( 27 | input clk, 28 | input rst_n, 29 | input [7:0] seg, // 数码管位选信号 30 | input [5:0] sel, // 数码管段选信号 31 | output reg shcp, // 移位寄存器时钟 32 | output reg stcp, // 存储寄存器时钟 33 | output reg ds, // 串行数据输出至 74HC595 芯片 34 | output oe // 始能信号 =0 有效 35 | ); 36 | 37 | reg [1:0] cnt; 38 | reg [3:0] cnt_bit; 39 | 40 | wire [15:0] data; 41 | 42 | assign data = {seg[7:0], sel[5:0]}; 43 | 44 | always @ (posedge clk) begin 45 | if (! rst_n) begin 46 | cnt <= 2'b0; 47 | cnt_bit <= 4'b0; 48 | ds <= 1'b0; 49 | shcp <= 1'b0; 50 | stcp <= 1'b0; 51 | end else begin 52 | cnt <= cnt + 2'h1; 53 | 54 | if (cnt == 2'h3) begin 55 | if (cnt_bit == 4'hd) 56 | cnt_bit <= 4'h0; 57 | else 58 | cnt_bit <= cnt_bit + 4'h1; 59 | end else 60 | cnt_bit <= cnt_bit; 61 | 62 | // output ds: 63 | if (cnt == 2'b0) 64 | ds <= data[cnt_bit]; 65 | else 66 | ds <= ds; 67 | 68 | // output shcp: 69 | if (cnt == 2'h2) 70 | shcp <= 1'b1; 71 | else if (cnt == 2'h0) 72 | shcp <= 1'b0; 73 | else 74 | shcp <= shcp; 75 | 76 | // output stcp: 77 | if (cnt == 2'h0 && cnt_bit == 4'h0) 78 | stcp <= 1'b1; 79 | else if (cnt == 2'h2 && cnt_bit == 4'h0) 80 | stcp <= 1'b0; 81 | else 82 | stcp <= stcp; 83 | end 84 | end 85 | 86 | assign oe = 1'b0; 87 | 88 | endmodule 89 | -------------------------------------------------------------------------------- /fsm/fsm.v: -------------------------------------------------------------------------------- 1 | // fsm 2 | 3 | module fsm 4 | ( 5 | input clk, 6 | input rst_n, 7 | input key_in, 8 | output reg [1:0] out 9 | ); 10 | 11 | localparam 12 | S1 = 2'b00, 13 | S2 = 2'b01, 14 | S3 = 2'b10, 15 | S4 = 2'b11; 16 | 17 | // current state: 18 | reg [1:0] cs; 19 | 20 | always @ (posedge clk or negedge rst_n) begin 21 | if (! rst_n) 22 | cs <= S1; 23 | else begin 24 | case (cs) 25 | S1: begin 26 | if (!key_in) 27 | cs <= S2; 28 | end 29 | S2: begin 30 | if (!key_in) 31 | cs <= S3; 32 | end 33 | S3: begin 34 | if (!key_in) 35 | cs <= S4; 36 | end 37 | S4: begin 38 | if (!key_in) 39 | cs <= S1; 40 | end 41 | default: cs <= S1; 42 | endcase 43 | end 44 | end 45 | 46 | always @ (posedge clk or negedge rst_n) begin 47 | if (! rst_n) 48 | out <= S1; 49 | else 50 | case (cs) 51 | S1: out <= S1; 52 | S2: out <= S2; 53 | S3: out <= S3; 54 | S4: out <= S4; 55 | default: out <= S1; 56 | endcase 57 | end 58 | endmodule 59 | -------------------------------------------------------------------------------- /fsm/key_filter.v: -------------------------------------------------------------------------------- 1 | // 按键消抖 2 | 3 | module key_filter 4 | #( 5 | parameter SYS_CLK = 50_000_000, // default to 50 MHz 6 | parameter FILTER_TIME = 50 // 毫秒, default to 50 ms 7 | ) 8 | ( 9 | input clk, 10 | input rst_n, 11 | input key_in, 12 | output reg key_out 13 | ); 14 | 15 | // 根据时钟频率计算指定时间内计数器最大值: 16 | localparam 17 | CLK_TIME = 1_000_000_000 / SYS_CLK, // 一个时钟周期的耗时ns 18 | CLK_MAX = FILTER_TIME * 1_000_000 / CLK_TIME, // 计数器最大值 19 | CNT_WIDTH = $clog2(CLK_MAX + 1); // 计数器位宽 20 | 21 | localparam [CNT_WIDTH-1:0] CNT_0 = 0; 22 | localparam [CNT_WIDTH-1:0] CNT_MAX = CLK_MAX; 23 | 24 | reg [CNT_WIDTH-1:0] cnt; 25 | 26 | always @ (posedge clk or negedge rst_n) begin 27 | if (! rst_n) begin 28 | cnt <= CNT_0; 29 | end else begin 30 | if (key_in == 1'b1) begin 31 | // key unpressed, keep 0: 32 | cnt <= CNT_0; 33 | end else begin 34 | // key pressed, cnt = 0, 1, 2, ... , MAX-1, MAX, MAX, ... 计数到最大值后保持 35 | cnt <= (cnt == CNT_MAX) ? CLK_MAX : cnt + 1; 36 | end 37 | end 38 | end 39 | 40 | always @ (posedge clk or negedge rst_n) begin 41 | if (! rst_n) begin 42 | key_out <= 1'b1; 43 | end else begin 44 | // key out is triggered at MAX-1: 45 | key_out <= (cnt == CNT_MAX - 1) ? 1'b0 : 1'b1; 46 | end 47 | end 48 | endmodule 49 | -------------------------------------------------------------------------------- /fsm/tb_fsm.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module tb_fsm(); 4 | 5 | reg clk; 6 | reg rst_n; 7 | reg key_in; 8 | wire [1:0] state; 9 | 10 | initial begin 11 | clk = 1'b1; 12 | rst_n = 1'b0; 13 | key_in = 1'b1; 14 | #100 15 | rst_n = 1'b1; 16 | #100 17 | key_in = 1'b0; 18 | #20 19 | key_in = 1'b1; 20 | #80 21 | key_in = 1'b0; 22 | #20 23 | key_in = 1'b1; 24 | #80 25 | key_in = 1'b0; 26 | #20 27 | key_in = 1'b1; 28 | #80 29 | key_in = 1'b0; 30 | #20 31 | key_in = 1'b1; 32 | #80 33 | key_in = 1'b0; 34 | #20 35 | key_in = 1'b1; 36 | #80 37 | $finish; 38 | end 39 | 40 | always #10 clk = ~clk; 41 | 42 | fsm component ( 43 | .clk (clk), 44 | .rst_n (rst_n), 45 | .key_in (key_in), 46 | .out (state) 47 | ); 48 | 49 | initial begin 50 | $dumpfile("tb_fsm.vcd"); 51 | $dumpvars(0, component); 52 | end 53 | endmodule 54 | -------------------------------------------------------------------------------- /fsm/top.v: -------------------------------------------------------------------------------- 1 | // display word by FSM 2 | 3 | module top ( 4 | input clk, 5 | input rst_n, 6 | input key_in, 7 | output shcp, 8 | output stcp, 9 | output ds, 10 | output oe 11 | ); 12 | localparam 13 | C = 8'b01100011, 14 | E = 8'b01100001, 15 | F = 8'b01110001, 16 | H = 8'b10010001, 17 | L = 8'b11100011, 18 | O = 8'b00000011, 19 | P = 8'b00110001, 20 | S = 8'b01001001, 21 | U = 8'b10000011; 22 | 23 | wire key1; 24 | wire [1:0] state; 25 | 26 | reg [47:0] data; 27 | 28 | wire [7:0] seg; 29 | wire [5:0] sel; 30 | 31 | fsm fsm_inst ( 32 | .clk (clk), 33 | .rst_n (rst_n), 34 | .key_in (key1), 35 | .out (state) 36 | ); 37 | 38 | key_filter key_filter_inst ( 39 | .clk (clk), 40 | .rst_n (rst_n), 41 | .key_in (key_in), 42 | .key_out (key1) 43 | ); 44 | 45 | digital_tube_display digital_tube_display_inst ( 46 | .clk (clk), 47 | .rst_n (rst_n), 48 | .seg (seg), 49 | .sel (sel), 50 | .shcp (shcp), 51 | .stcp (stcp), 52 | .ds (ds), 53 | .oe (oe) 54 | ); 55 | 56 | digital_tube_data digital_tube_data_inst ( 57 | .clk (clk), 58 | .rst_n (rst_n), 59 | .data (data), 60 | .seg (seg), 61 | .sel (sel) 62 | ); 63 | 64 | always @ (posedge clk or negedge rst_n) begin 65 | if (! rst_n) begin 66 | data <= { E, E, E, E, E, E }; 67 | end else begin 68 | case (state) 69 | 2'b00: data <= { C, H, O, O, S, E }; 70 | 2'b01: data <= { E, P, O, C, H, S }; 71 | 2'b10: data <= { P, U, L, S, E, S }; 72 | 2'b11: data <= { S, C, H, O, O, L }; 73 | endcase 74 | end 75 | end 76 | 77 | endmodule 78 | -------------------------------------------------------------------------------- /full_adder/full_adder.v: -------------------------------------------------------------------------------- 1 | `include "half_adder.v" 2 | 3 | module full_adder( 4 | input a, 5 | input b, 6 | input cin, 7 | output carry, 8 | output sum 9 | ); 10 | 11 | wire t_carry1; 12 | wire t_carry2; 13 | wire t_sum; 14 | 15 | half_adder h1( 16 | .a(a), 17 | .b(b), 18 | .carry(t_carry1), 19 | .sum(t_sum) 20 | ); 21 | 22 | half_adder h2( 23 | .a(t_sum), 24 | .b(cin), 25 | .carry(t_carry2), 26 | .sum(sum) 27 | ); 28 | 29 | assign carry = t_carry1 | t_carry2; 30 | 31 | endmodule 32 | -------------------------------------------------------------------------------- /full_adder/full_adder_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module full_adder_tb (); 4 | 5 | reg a; 6 | reg b; 7 | reg cin; 8 | wire carry; 9 | wire sum; 10 | 11 | full_adder full_adder_instance( 12 | .a(a), 13 | .b(b), 14 | .cin(cin), 15 | .carry(carry), 16 | .sum(sum) 17 | ); 18 | 19 | task assert(input a, b, cin, carry, sum); 20 | begin 21 | $display("Assert: a = %b, b = %b, cin=%b, carry = %b, sum = %b", a, b, cin, carry, sum); 22 | if ({1'b0, cin} + {1'b0, a} + {1'b0, b} !== {carry, sum}) begin 23 | $display("Assert failed!"); 24 | $stop; 25 | end 26 | end 27 | endtask 28 | 29 | initial begin 30 | a = 1'b0; 31 | b = 1'b0; 32 | cin = 1'b0; 33 | #10 34 | assert(a, b, cin, carry, sum); 35 | #10 36 | a = 1'b0; 37 | b = 1'b0; 38 | cin = 1'b1; 39 | #10 40 | assert(a, b, cin, carry, sum); 41 | #10 42 | a = 1'b0; 43 | b = 1'b1; 44 | cin = 1'b0; 45 | #10 46 | assert(a, b, cin, carry, sum); 47 | #10 48 | a = 1'b0; 49 | b = 1'b1; 50 | cin = 1'b1; 51 | #10 52 | assert(a, b, cin, carry, sum); 53 | #10 54 | a = 1'b1; 55 | b = 1'b0; 56 | cin = 1'b0; 57 | #10 58 | assert(a, b, cin, carry, sum); 59 | #10 60 | a = 1'b1; 61 | b = 1'b0; 62 | cin = 1'b1; 63 | #10 64 | assert(a, b, cin, carry, sum); 65 | #10 66 | a = 1'b1; 67 | b = 1'b1; 68 | cin = 1'b0; 69 | #10 70 | assert(a, b, cin, carry, sum); 71 | #10 72 | a = 1'b1; 73 | b = 1'b1; 74 | cin = 1'b1; 75 | #10 76 | assert(a, b, cin, carry, sum); 77 | #10 78 | $finish; 79 | end 80 | 81 | initial begin 82 | $dumpfile("test.vcd"); 83 | $dumpvars(0, full_adder_instance); 84 | end 85 | 86 | endmodule 87 | -------------------------------------------------------------------------------- /full_adder/half_adder.v: -------------------------------------------------------------------------------- 1 | /* 2 | Half Adder: 3 | 4 | a b carry sum 5 | --------------- 6 | 0 + 0 = 0 0 7 | 0 + 1 = 0 1 8 | 1 + 0 = 0 1 9 | 1 + 1 = 1 0 10 | 11 | */ 12 | 13 | module half_adder( 14 | input a, 15 | input b, 16 | output carry, 17 | output sum 18 | ); 19 | assign carry = a & b; 20 | assign sum = a ^ b; 21 | endmodule 22 | -------------------------------------------------------------------------------- /gate/gate.v: -------------------------------------------------------------------------------- 1 | // AND/OR gate controlled by keys. 2 | 3 | module led( 4 | input k1, 5 | input k2, 6 | input k3, 7 | input k4, 8 | output a, 9 | output b 10 | ); 11 | assign a = k1 & k2; 12 | assign b = k3 | k4; 13 | endmodule 14 | -------------------------------------------------------------------------------- /half_adder/half_adder.svg: -------------------------------------------------------------------------------- 1 | abcoutsum -------------------------------------------------------------------------------- /half_adder/half_adder.v: -------------------------------------------------------------------------------- 1 | /* 2 | Half Adder: 3 | 4 | a b carry sum 5 | --------------- 6 | 0 + 0 = 0 0 7 | 0 + 1 = 0 1 8 | 1 + 0 = 0 1 9 | 1 + 1 = 1 0 10 | 11 | */ 12 | 13 | module half_adder( 14 | input a, 15 | input b, 16 | output carry, 17 | output sum 18 | ); 19 | assign carry = a & b; 20 | assign sum = a ^ b; 21 | endmodule 22 | -------------------------------------------------------------------------------- /half_adder/half_adder_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module half_adder_tb (); 4 | 5 | reg a; 6 | reg b; 7 | wire carry; 8 | wire sum; 9 | 10 | half_adder half_adder_instance( 11 | .a(a), 12 | .b(b), 13 | .carry(carry), 14 | .sum(sum) 15 | ); 16 | 17 | task assert(input a, b, carry, sum); 18 | begin 19 | $display("Assert: a = %b, b = %b, carry = %b, sum = %b", a, b, carry, sum); 20 | if ({1'b0, a} + {1'b0, b} !== {carry, sum}) begin 21 | $display("Assert failed!"); 22 | $stop; 23 | end 24 | end 25 | endtask 26 | 27 | initial begin 28 | a = 1'b0; 29 | b = 1'b0; 30 | #10 31 | assert(a, b, carry, sum); 32 | #10 33 | a = 1'b1; 34 | b = 1'b0; 35 | #10 36 | assert(a, b, carry, sum); 37 | #10 38 | a = 1'b0; 39 | b = 1'b1; 40 | #10 41 | assert(a, b, carry, sum); 42 | #10 43 | a = 1'b1; 44 | b = 1'b1; 45 | #10 46 | assert(a, b, carry, sum); 47 | #10 48 | a = 1'b0; 49 | b = 1'b0; 50 | #10 51 | $finish; 52 | end 53 | 54 | initial begin 55 | $dumpfile("test.vcd"); 56 | $dumpvars(0, half_adder_instance); 57 | end 58 | 59 | endmodule 60 | -------------------------------------------------------------------------------- /hdmi_bitmap_display/README.md: -------------------------------------------------------------------------------- 1 | # Bitmap Display 2 | 3 | Display image as HDMI output. 4 | 5 | # Bitmap Storage 6 | 7 | Pixel data = ARGB = 4 Bytes. 8 | 9 | Memory = 640 x 480 x 4 = 1228.8 KB = 1.2288 MB 10 | 11 | Address = 0x000B8000 ~ 0x001E3FFF 12 | -------------------------------------------------------------------------------- /hdmi_bitmap_display/fifo_uart.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "FIFO" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "fifo_uart.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "fifo_uart_inst.v"] 6 | -------------------------------------------------------------------------------- /hdmi_bitmap_display/fifo_uart_inst.v: -------------------------------------------------------------------------------- 1 | fifo_uart fifo_uart_inst ( 2 | .data ( data_sig ), 3 | .rdclk ( rdclk_sig ), 4 | .rdreq ( rdreq_sig ), 5 | .wrclk ( wrclk_sig ), 6 | .wrreq ( wrreq_sig ), 7 | .q ( q_sig ), 8 | .rdempty ( rdempty_sig ), 9 | .rdusedw ( rdusedw_sig ), 10 | .wrfull ( wrfull_sig ), 11 | .wrusedw ( wrusedw_sig ) 12 | ); 13 | -------------------------------------------------------------------------------- /hdmi_display/README.md: -------------------------------------------------------------------------------- 1 | # HDMI Display 2 | 3 | Display 80x25 text mode as HDMI output. 4 | 5 | # Generate Font for ROM 6 | 7 | The ROM file `font.mif` is generated by script: 8 | 9 | ``` 10 | $ ../resources/script/gen_font.py \ 11 | --input ../resources/font/ascii-font.png \ 12 | --output ./font.mif 13 | ``` 14 | 15 | # Generate Buffer for RAM 16 | 17 | The RAM file `char-buffer.mif` is generated by script: 18 | 19 | ``` 20 | $ ../resources/script/gen_char_buffer.py \ 21 | --input ../resources/font/init-screen.txt \ 22 | --output ./char-buffer.mif 23 | ``` 24 | 25 | # Generate Index Color to RGB 26 | 27 | The source file `index_color_to_rgb.v` is generated by script: 28 | 29 | ``` 30 | $ ../resources/script/gen_index_color_to_rgb.py \ 31 | --width 24 \ 32 | --output ./index_color_to_rgb.v 33 | ``` 34 | -------------------------------------------------------------------------------- /hdmi_display/clk_delay.v: -------------------------------------------------------------------------------- 1 | 2 | module clk_delay #( 3 | parameter WIDTH = 8 4 | ) 5 | ( 6 | input wire clk, 7 | input wire [WIDTH-1:0] in_data, 8 | output reg [WIDTH-1:0] out_data 9 | ); 10 | always @ (posedge clk) begin 11 | out_data <= in_data; 12 | end 13 | endmodule 14 | -------------------------------------------------------------------------------- /hdmi_display/ddio.bsf: -------------------------------------------------------------------------------- 1 | /* 2 | WARNING: Do NOT edit the input and output ports in this file in a text 3 | editor if you plan to continue editing the block that represents it in 4 | the Block Editor! File corruption is VERY likely to occur. 5 | */ 6 | /* 7 | Copyright (C) 2020 Intel Corporation. All rights reserved. 8 | Your use of Intel Corporation's design tools, logic functions 9 | and other software and tools, and any partner logic 10 | functions, and any output files from any of the foregoing 11 | (including device programming or simulation files), and any 12 | associated documentation or information are expressly subject 13 | to the terms and conditions of the Intel Program License 14 | Subscription Agreement, the Intel Quartus Prime License Agreement, 15 | the Intel FPGA IP License Agreement, or other applicable license 16 | agreement, including, without limitation, that your use is for 17 | the sole purpose of programming logic devices manufactured by 18 | Intel and sold by Intel or its authorized distributors. Please 19 | refer to the applicable agreement for further details, at 20 | https://fpgasoftware.intel.com/eula. 21 | */ 22 | (header "symbol" (version "1.2")) 23 | (symbol 24 | (rect 0 0 192 112) 25 | (text "ddio" (rect 84 0 112 16)(font "Arial" (font_size 10))) 26 | (text "inst" (rect 8 96 25 108)(font "Arial" )) 27 | (port 28 | (pt 0 48) 29 | (input) 30 | (text "datain_h[0]" (rect 0 0 62 14)(font "Arial" (font_size 8))) 31 | (text "datain_h[0]" (rect 4 34 55 47)(font "Arial" (font_size 8))) 32 | (line (pt 0 48)(pt 64 48)(line_width 3)) 33 | ) 34 | (port 35 | (pt 0 64) 36 | (input) 37 | (text "datain_l[0]" (rect 0 0 57 14)(font "Arial" (font_size 8))) 38 | (text "datain_l[0]" (rect 4 50 51 63)(font "Arial" (font_size 8))) 39 | (line (pt 0 64)(pt 64 64)(line_width 3)) 40 | ) 41 | (port 42 | (pt 0 80) 43 | (input) 44 | (text "outclock" (rect 0 0 47 14)(font "Arial" (font_size 8))) 45 | (text "outclock" (rect 4 66 42 79)(font "Arial" (font_size 8))) 46 | (line (pt 0 80)(pt 64 80)) 47 | ) 48 | (port 49 | (pt 192 48) 50 | (output) 51 | (text "dataout[0]" (rect 0 0 56 14)(font "Arial" (font_size 8))) 52 | (text "dataout[0]" (rect 141 34 187 47)(font "Arial" (font_size 8))) 53 | (line (pt 192 48)(pt 128 48)(line_width 3)) 54 | ) 55 | (drawing 56 | (line (pt 64 32)(pt 128 32)) 57 | (line (pt 128 32)(pt 128 96)) 58 | (line (pt 64 96)(pt 128 96)) 59 | (line (pt 64 32)(pt 64 96)) 60 | (line (pt 0 0)(pt 192 0)) 61 | (line (pt 192 0)(pt 192 112)) 62 | (line (pt 0 112)(pt 192 112)) 63 | (line (pt 0 0)(pt 0 112)) 64 | ) 65 | ) 66 | -------------------------------------------------------------------------------- /hdmi_display/ddio.ppf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /hdmi_display/ddio.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "ALTDDIO_OUT" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "ddio.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "ddio.bsf"] 6 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "ddio_inst.v"] 7 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "ddio.ppf"] 8 | -------------------------------------------------------------------------------- /hdmi_display/ddio.v: -------------------------------------------------------------------------------- 1 | // megafunction wizard: %ALTDDIO_OUT% 2 | // GENERATION: STANDARD 3 | // VERSION: WM1.0 4 | // MODULE: ALTDDIO_OUT 5 | 6 | // ============================================================ 7 | // File Name: ddio.v 8 | // Megafunction Name(s): 9 | // ALTDDIO_OUT 10 | // 11 | // Simulation Library Files(s): 12 | // altera_mf 13 | // ============================================================ 14 | // ************************************************************ 15 | // THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! 16 | // 17 | // 20.1.1 Build 720 11/11/2020 SJ Lite Edition 18 | // ************************************************************ 19 | 20 | 21 | //Copyright (C) 2020 Intel Corporation. All rights reserved. 22 | //Your use of Intel Corporation's design tools, logic functions 23 | //and other software and tools, and any partner logic 24 | //functions, and any output files from any of the foregoing 25 | //(including device programming or simulation files), and any 26 | //associated documentation or information are expressly subject 27 | //to the terms and conditions of the Intel Program License 28 | //Subscription Agreement, the Intel Quartus Prime License Agreement, 29 | //the Intel FPGA IP License Agreement, or other applicable license 30 | //agreement, including, without limitation, that your use is for 31 | //the sole purpose of programming logic devices manufactured by 32 | //Intel and sold by Intel or its authorized distributors. Please 33 | //refer to the applicable agreement for further details, at 34 | //https://fpgasoftware.intel.com/eula. 35 | 36 | 37 | // synopsys translate_off 38 | `timescale 1 ps / 1 ps 39 | // synopsys translate_on 40 | module ddio ( 41 | datain_h, 42 | datain_l, 43 | outclock, 44 | dataout); 45 | 46 | input [0:0] datain_h; 47 | input [0:0] datain_l; 48 | input outclock; 49 | output [0:0] dataout; 50 | 51 | wire [0:0] sub_wire0; 52 | wire [0:0] dataout = sub_wire0[0:0]; 53 | 54 | altddio_out ALTDDIO_OUT_component ( 55 | .datain_h (datain_h), 56 | .datain_l (datain_l), 57 | .outclock (outclock), 58 | .dataout (sub_wire0), 59 | .aclr (1'b0), 60 | .aset (1'b0), 61 | .oe (1'b1), 62 | .oe_out (), 63 | .outclocken (1'b1), 64 | .sclr (1'b0), 65 | .sset (1'b0)); 66 | defparam 67 | ALTDDIO_OUT_component.extend_oe_disable = "OFF", 68 | ALTDDIO_OUT_component.intended_device_family = "Cyclone IV E", 69 | ALTDDIO_OUT_component.invert_output = "OFF", 70 | ALTDDIO_OUT_component.lpm_hint = "UNUSED", 71 | ALTDDIO_OUT_component.lpm_type = "altddio_out", 72 | ALTDDIO_OUT_component.oe_reg = "UNREGISTERED", 73 | ALTDDIO_OUT_component.power_up_high = "OFF", 74 | ALTDDIO_OUT_component.width = 1; 75 | 76 | 77 | endmodule 78 | 79 | // ============================================================ 80 | // CNX file retrieval info 81 | // ============================================================ 82 | // Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all 83 | // Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E" 84 | // Retrieval info: CONSTANT: EXTEND_OE_DISABLE STRING "OFF" 85 | // Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E" 86 | // Retrieval info: CONSTANT: INVERT_OUTPUT STRING "OFF" 87 | // Retrieval info: CONSTANT: LPM_HINT STRING "UNUSED" 88 | // Retrieval info: CONSTANT: LPM_TYPE STRING "altddio_out" 89 | // Retrieval info: CONSTANT: OE_REG STRING "UNREGISTERED" 90 | // Retrieval info: CONSTANT: POWER_UP_HIGH STRING "OFF" 91 | // Retrieval info: CONSTANT: WIDTH NUMERIC "1" 92 | // Retrieval info: USED_PORT: datain_h 0 0 1 0 INPUT NODEFVAL "datain_h[0..0]" 93 | // Retrieval info: CONNECT: @datain_h 0 0 1 0 datain_h 0 0 1 0 94 | // Retrieval info: USED_PORT: datain_l 0 0 1 0 INPUT NODEFVAL "datain_l[0..0]" 95 | // Retrieval info: CONNECT: @datain_l 0 0 1 0 datain_l 0 0 1 0 96 | // Retrieval info: USED_PORT: dataout 0 0 1 0 OUTPUT NODEFVAL "dataout[0..0]" 97 | // Retrieval info: CONNECT: dataout 0 0 1 0 @dataout 0 0 1 0 98 | // Retrieval info: USED_PORT: outclock 0 0 0 0 INPUT_CLK_EXT NODEFVAL "outclock" 99 | // Retrieval info: CONNECT: @outclock 0 0 0 0 outclock 0 0 0 0 100 | // Retrieval info: GEN_FILE: TYPE_NORMAL ddio.v TRUE FALSE 101 | // Retrieval info: GEN_FILE: TYPE_NORMAL ddio.qip TRUE FALSE 102 | // Retrieval info: GEN_FILE: TYPE_NORMAL ddio.bsf TRUE TRUE 103 | // Retrieval info: GEN_FILE: TYPE_NORMAL ddio_inst.v TRUE TRUE 104 | // Retrieval info: GEN_FILE: TYPE_NORMAL ddio_bb.v FALSE TRUE 105 | // Retrieval info: GEN_FILE: TYPE_NORMAL ddio.inc FALSE TRUE 106 | // Retrieval info: GEN_FILE: TYPE_NORMAL ddio.cmp FALSE TRUE 107 | // Retrieval info: GEN_FILE: TYPE_NORMAL ddio.ppf TRUE FALSE 108 | // Retrieval info: LIB_FILE: altera_mf 109 | -------------------------------------------------------------------------------- /hdmi_display/ddio_inst.v: -------------------------------------------------------------------------------- 1 | ddio ddio_inst ( 2 | .datain_h ( datain_h_sig ), 3 | .datain_l ( datain_l_sig ), 4 | .outclock ( outclock_sig ), 5 | .dataout ( dataout_sig ) 6 | ); 7 | -------------------------------------------------------------------------------- /hdmi_display/hdmi_ctrl.v: -------------------------------------------------------------------------------- 1 | 2 | module hdmi_ctrl 3 | ( 4 | input clk_1x, 5 | input clk_5x, 6 | input rst_n, 7 | 8 | input [7:0] rgb_r, 9 | input [7:0] rgb_g, 10 | input [7:0] rgb_b, 11 | 12 | input hsync, 13 | input vsync, 14 | input de, 15 | 16 | output hdmi_clk_p, 17 | output hdmi_clk_n, 18 | output hdmi_r_p, 19 | output hdmi_r_n, 20 | output hdmi_g_p, 21 | output hdmi_g_n, 22 | output hdmi_b_p, 23 | output hdmi_b_n 24 | ); 25 | 26 | wire [9:0] tmds_r; 27 | wire [9:0] tmds_g; 28 | wire [9:0] tmds_b; 29 | 30 | encode encode_r ( 31 | .clk (clk_1x), 32 | .rst_n (rst_n), 33 | .c0 (hsync), 34 | .c1 (vsync), 35 | .de (de), 36 | .data_in (rgb_r), 37 | .data_out (tmds_r) 38 | ); 39 | 40 | encode encode_g ( 41 | .clk (clk_1x), 42 | .rst_n (rst_n), 43 | .c0 (hsync), 44 | .c1 (vsync), 45 | .de (de), 46 | .data_in (rgb_g), 47 | .data_out (tmds_g) 48 | ); 49 | 50 | encode encode_b ( 51 | .clk (clk_1x), 52 | .rst_n (rst_n), 53 | .c0 (hsync), 54 | .c1 (vsync), 55 | .de (de), 56 | .data_in (rgb_b), 57 | .data_out (tmds_b) 58 | ); 59 | 60 | par_to_ser par_to_ser_r ( 61 | .clk_5x (clk_5x), 62 | .par_data (tmds_r), 63 | .ser_data_p (hdmi_r_p), 64 | .ser_data_n (hdmi_r_n) 65 | ); 66 | 67 | par_to_ser par_to_ser_g ( 68 | .clk_5x (clk_5x), 69 | .par_data (tmds_g), 70 | .ser_data_p (hdmi_g_p), 71 | .ser_data_n (hdmi_g_n) 72 | ); 73 | 74 | par_to_ser par_to_ser_b ( 75 | .clk_5x (clk_5x), 76 | .par_data (tmds_b), 77 | .ser_data_p (hdmi_b_p), 78 | .ser_data_n (hdmi_b_n) 79 | ); 80 | 81 | par_to_ser par_to_ser_clk ( 82 | .clk_5x (clk_5x), 83 | .par_data (10'b1111100000), 84 | .ser_data_p (hdmi_clk_p), 85 | .ser_data_n (hdmi_clk_n) 86 | ); 87 | 88 | endmodule 89 | -------------------------------------------------------------------------------- /hdmi_display/hdmi_display.csv: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Intel Corporation. All rights reserved. 2 | # Your use of Intel Corporation's design tools, logic functions 3 | # and other software and tools, and any partner logic 4 | # functions, and any output files from any of the foregoing 5 | # (including device programming or simulation files), and any 6 | # associated documentation or information are expressly subject 7 | # to the terms and conditions of the Intel Program License 8 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 9 | # the Intel FPGA IP License Agreement, or other applicable license 10 | # agreement, including, without limitation, that your use is for 11 | # the sole purpose of programming logic devices manufactured by 12 | # Intel and sold by Intel or its authorized distributors. Please 13 | # refer to the applicable agreement for further details, at 14 | # https://fpgasoftware.intel.com/eula. 15 | 16 | # Quartus Prime Version 20.1.1 Build 720 11/11/2020 SJ Lite Edition 17 | # File: C:\Users\Michael\Git\GitHub\learn-verilog\hdmi_display\hdmi_display.csv 18 | # Generated on: Wed Oct 05 16:40:50 2022 19 | 20 | # Note: The column header names should not be changed if you wish to import this .csv file into the Quartus Prime software. 21 | 22 | To,Direction,Location,I/O Bank,VREF Group,Fitter Location,I/O Standard,Reserved,Current Strength,Slew Rate,Differential Pair,Strict Preservation 23 | ddc_scl,Output,PIN_N13,5,B5_N0,PIN_K1,,,,,, 24 | ddc_sda,Output,PIN_M12,5,B5_N0,PIN_N5,,,,,, 25 | sys_clk,Input,PIN_E1,1,B1_N0,PIN_E16,,,,,, 26 | sys_rst_n,Input,PIN_M15,5,B5_N0,PIN_E15,,,,,, 27 | tmds_clk_n,Output,PIN_P16,5,B5_N0,PIN_L3,,,,,, 28 | tmds_clk_p,Output,PIN_R16,5,B5_N0,PIN_L15,,,,,, 29 | tmds_data_n[2],Output,PIN_K16,5,B5_N0,PIN_E5,,,,,, 30 | tmds_data_n[1],Output,PIN_L16,5,B5_N0,PIN_E11,,,,,, 31 | tmds_data_n[0],Output,PIN_N16,5,B5_N0,PIN_K15,,,,,, 32 | tmds_data_p[2],Output,PIN_K15,5,B5_N0,PIN_M11,,,,,, 33 | tmds_data_p[1],Output,PIN_L15,5,B5_N0,PIN_D3,,,,,, 34 | tmds_data_p[0],Output,PIN_N15,5,B5_N0,PIN_A13,,,,,, 35 | -------------------------------------------------------------------------------- /hdmi_display/index_color_to_rgb.v: -------------------------------------------------------------------------------- 1 | // VGA 16 Color Palette: 2 | // https://en.wikipedia.org/wiki/Color_Graphics_Adapter 3 | 4 | module index_color_to_rgb ( 5 | input wire [3:0] color_index, 6 | output reg [23:0] color_rgb 7 | ); 8 | always @ (*) begin 9 | case (color_index) 10 | 4'd0: color_rgb = 24'b00000000_00000000_00000000; // #000000 = black 11 | 4'd1: color_rgb = 24'b00000000_00000000_10101010; // #0000aa = blue 12 | 4'd2: color_rgb = 24'b00000000_10101010_00000000; // #00aa00 = green 13 | 4'd3: color_rgb = 24'b00000000_10101010_10101010; // #00aaaa = cyan 14 | 4'd4: color_rgb = 24'b10101010_00000000_00000000; // #aa0000 = red 15 | 4'd5: color_rgb = 24'b10101010_00000000_10101010; // #aa00aa = magenta 16 | 4'd6: color_rgb = 24'b10101010_01010101_00000000; // #aa5500 = brown 17 | 4'd7: color_rgb = 24'b10101010_10101010_10101010; // #aaaaaa = light gray 18 | 4'd8: color_rgb = 24'b01010101_01010101_01010101; // #555555 = dark gray 19 | 4'd9: color_rgb = 24'b01010101_01010101_11111111; // #5555ff = light blue 20 | 4'd10: color_rgb = 24'b01010101_11111111_01010101; // #55ff55 = light green 21 | 4'd11: color_rgb = 24'b01010101_11111111_11111111; // #55ffff = light cyan 22 | 4'd12: color_rgb = 24'b11111111_01010101_01010101; // #ff5555 = light red 23 | 4'd13: color_rgb = 24'b11111111_01010101_11111111; // #ff55ff = light magenta 24 | 4'd14: color_rgb = 24'b11111111_11111111_01010101; // #ffff55 = yellow 25 | 4'd15: color_rgb = 24'b11111111_11111111_11111111; // #ffffff = white 26 | endcase 27 | end 28 | endmodule 29 | -------------------------------------------------------------------------------- /hdmi_display/par_to_ser.v: -------------------------------------------------------------------------------- 1 | // par_to_ser 2 | 3 | module par_to_ser 4 | ( 5 | input clk_5x, 6 | input [9:0] par_data, 7 | 8 | output ser_data_p, 9 | output ser_data_n 10 | ); 11 | 12 | //wire define 13 | wire [4:0] data_rise = {par_data[8],par_data[6], 14 | par_data[4],par_data[2],par_data[0]}; 15 | wire [4:0] data_fall = {par_data[9],par_data[7], 16 | par_data[5],par_data[3],par_data[1]}; 17 | 18 | //reg define 19 | reg [4:0] data_rise_s = 0; 20 | reg [4:0] data_fall_s = 0; 21 | reg [2:0] cnt = 0; 22 | 23 | always @ (posedge clk_5x) begin 24 | cnt <= (cnt[2]) ? 3'd0 : cnt + 3'd1; 25 | data_rise_s <= cnt[2] ? data_rise : data_rise_s[4:1]; 26 | data_fall_s <= cnt[2] ? data_fall : data_fall_s[4:1]; 27 | 28 | end 29 | 30 | ddio ddio_0 ( 31 | .datain_h (data_rise_s[0] ), 32 | .datain_l (data_fall_s[0] ), 33 | .outclock (~clk_5x ), 34 | .dataout (ser_data_p ) 35 | ); 36 | 37 | ddio ddio_1 ( 38 | .datain_h (~data_rise_s[0]), 39 | .datain_l (~data_fall_s[0]), 40 | .outclock (~clk_5x ), 41 | .dataout (ser_data_n ) 42 | ); 43 | 44 | endmodule 45 | -------------------------------------------------------------------------------- /hdmi_display/pixel_index_color.v: -------------------------------------------------------------------------------- 1 | 2 | module pixel_index_color ( 3 | input valid, 4 | input [7:0] font_line_data, 5 | input [2:0] char_pix_x, 6 | input [7:0] bg_fg_index, 7 | output [3:0] color_index 8 | ); 9 | reg pix; 10 | 11 | always @ (*) begin 12 | case (char_pix_x) 13 | 3'd0: pix = font_line_data[7]; 14 | 3'd1: pix = font_line_data[6]; 15 | 3'd2: pix = font_line_data[5]; 16 | 3'd3: pix = font_line_data[4]; 17 | 3'd4: pix = font_line_data[3]; 18 | 3'd5: pix = font_line_data[2]; 19 | 3'd6: pix = font_line_data[1]; 20 | 3'd7: pix = font_line_data[0]; 21 | endcase 22 | end 23 | 24 | // if pix is 1, return fg color index, otherwise bg color: 25 | assign color_index = valid ? (pix == 1'b1 ? bg_fg_index[3:0] : bg_fg_index[7:4]) : 4'd0; 26 | 27 | endmodule 28 | -------------------------------------------------------------------------------- /hdmi_display/pixel_to_char.v: -------------------------------------------------------------------------------- 1 | module pixel_to_char ( 2 | input pix_req, 3 | // pixel x of screen: 0 ~ 639: 4 | input [9:0] pix_x, 5 | // pixel y of screen: 0 ~ 479: 6 | input [9:0] pix_y, 7 | 8 | // is char valid: 9 | output reg char_valid, 10 | // char index: 0 ~ 1999: 11 | output wire [10:0] char_index, 12 | // pixel x of char: 0 ~ 7: 13 | output reg [2:0] char_pixel_x, 14 | // pixel y of char: 0 ~ 15: 15 | output reg [3:0] char_pixel_y 16 | ); 17 | 18 | parameter PIX_Y_START = 10'd32, 19 | PIX_Y_END = PIX_Y_START + 25 * 16; 20 | 21 | reg [10:0] row; 22 | reg [10:0] col; 23 | 24 | always @ (*) begin 25 | if (pix_req && pix_y >= PIX_Y_START && pix_y < PIX_Y_END) begin 26 | char_valid = 1'b1; 27 | row = (pix_y - PIX_Y_START) >> 4; 28 | col = pix_x >> 3; 29 | char_pixel_x = pix_x[2:0] & 3'b111; 30 | char_pixel_y = pix_y[3:0] & 4'b1111; 31 | end 32 | else begin 33 | char_valid = 1'b0; 34 | row = 11'b0; 35 | col = 11'b0; 36 | char_pixel_x = 3'b0; 37 | char_pixel_y = 4'b0; 38 | end 39 | end 40 | 41 | assign char_index = row * 11'd80 + col; 42 | endmodule 43 | -------------------------------------------------------------------------------- /hdmi_display/pll.inc: -------------------------------------------------------------------------------- 1 | --Copyright (C) 2020 Intel Corporation. All rights reserved. 2 | --Your use of Intel Corporation's design tools, logic functions 3 | --and other software and tools, and any partner logic 4 | --functions, and any output files from any of the foregoing 5 | --(including device programming or simulation files), and any 6 | --associated documentation or information are expressly subject 7 | --to the terms and conditions of the Intel Program License 8 | --Subscription Agreement, the Intel Quartus Prime License Agreement, 9 | --the Intel FPGA IP License Agreement, or other applicable license 10 | --agreement, including, without limitation, that your use is for 11 | --the sole purpose of programming logic devices manufactured by 12 | --Intel and sold by Intel or its authorized distributors. Please 13 | --refer to the applicable agreement for further details, at 14 | --https://fpgasoftware.intel.com/eula. 15 | 16 | 17 | FUNCTION pll 18 | ( 19 | areset, 20 | inclk0 21 | ) 22 | 23 | RETURNS ( 24 | c0, 25 | c1, 26 | locked 27 | ); 28 | -------------------------------------------------------------------------------- /hdmi_display/pll.ppf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /hdmi_display/pll.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "ALTPLL" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "pll.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll_inst.v"] 6 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll.inc"] 7 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll.ppf"] 8 | -------------------------------------------------------------------------------- /hdmi_display/pll_inst.v: -------------------------------------------------------------------------------- 1 | pll pll_inst ( 2 | .areset ( areset_sig ), 3 | .inclk0 ( inclk0_sig ), 4 | .c0 ( c0_sig ), 5 | .c1 ( c1_sig ), 6 | .locked ( locked_sig ) 7 | ); 8 | -------------------------------------------------------------------------------- /hdmi_display/ram_buffer.bsf: -------------------------------------------------------------------------------- 1 | /* 2 | WARNING: Do NOT edit the input and output ports in this file in a text 3 | editor if you plan to continue editing the block that represents it in 4 | the Block Editor! File corruption is VERY likely to occur. 5 | */ 6 | /* 7 | Copyright (C) 2020 Intel Corporation. All rights reserved. 8 | Your use of Intel Corporation's design tools, logic functions 9 | and other software and tools, and any partner logic 10 | functions, and any output files from any of the foregoing 11 | (including device programming or simulation files), and any 12 | associated documentation or information are expressly subject 13 | to the terms and conditions of the Intel Program License 14 | Subscription Agreement, the Intel Quartus Prime License Agreement, 15 | the Intel FPGA IP License Agreement, or other applicable license 16 | agreement, including, without limitation, that your use is for 17 | the sole purpose of programming logic devices manufactured by 18 | Intel and sold by Intel or its authorized distributors. Please 19 | refer to the applicable agreement for further details, at 20 | https://fpgasoftware.intel.com/eula. 21 | */ 22 | (header "symbol" (version "1.2")) 23 | (symbol 24 | (rect 0 0 256 152) 25 | (text "ram_buffer" (rect 98 0 168 16)(font "Arial" (font_size 10))) 26 | (text "inst" (rect 8 136 25 148)(font "Arial" )) 27 | (port 28 | (pt 0 32) 29 | (input) 30 | (text "data[15..0]" (rect 0 0 60 14)(font "Arial" (font_size 8))) 31 | (text "data[15..0]" (rect 4 18 53 31)(font "Arial" (font_size 8))) 32 | (line (pt 0 32)(pt 112 32)(line_width 3)) 33 | ) 34 | (port 35 | (pt 0 48) 36 | (input) 37 | (text "wraddress[10..0]" (rect 0 0 99 14)(font "Arial" (font_size 8))) 38 | (text "wraddress[10..0]" (rect 4 34 86 47)(font "Arial" (font_size 8))) 39 | (line (pt 0 48)(pt 112 48)(line_width 3)) 40 | ) 41 | (port 42 | (pt 0 64) 43 | (input) 44 | (text "wren" (rect 0 0 30 14)(font "Arial" (font_size 8))) 45 | (text "wren" (rect 4 50 28 63)(font "Arial" (font_size 8))) 46 | (line (pt 0 64)(pt 112 64)) 47 | ) 48 | (port 49 | (pt 0 88) 50 | (input) 51 | (text "rdaddress[10..0]" (rect 0 0 94 14)(font "Arial" (font_size 8))) 52 | (text "rdaddress[10..0]" (rect 4 74 82 87)(font "Arial" (font_size 8))) 53 | (line (pt 0 88)(pt 112 88)(line_width 3)) 54 | ) 55 | (port 56 | (pt 0 112) 57 | (input) 58 | (text "wrclock" (rect 0 0 46 14)(font "Arial" (font_size 8))) 59 | (text "wrclock" (rect 4 98 41 111)(font "Arial" (font_size 8))) 60 | (line (pt 0 112)(pt 98 112)) 61 | ) 62 | (port 63 | (pt 0 128) 64 | (input) 65 | (text "rdclock" (rect 0 0 41 14)(font "Arial" (font_size 8))) 66 | (text "rdclock" (rect 4 114 37 127)(font "Arial" (font_size 8))) 67 | (line (pt 0 128)(pt 104 128)) 68 | ) 69 | (port 70 | (pt 256 88) 71 | (output) 72 | (text "q[15..0]" (rect 0 0 42 14)(font "Arial" (font_size 8))) 73 | (text "q[15..0]" (rect 217 74 251 87)(font "Arial" (font_size 8))) 74 | (line (pt 256 88)(pt 168 88)(line_width 3)) 75 | ) 76 | (drawing 77 | (text "2000 Word(s)" (rect 137 -5 236 187)(font "Arial" )(vertical)) 78 | (text "RAM" (rect 148 -16 229 151)(font "Arial" )(vertical)) 79 | (text "Block Type: M9K" (rect 40 141 150 293)(font "Arial" )) 80 | (line (pt 128 24)(pt 168 24)) 81 | (line (pt 168 24)(pt 168 96)) 82 | (line (pt 168 96)(pt 128 96)) 83 | (line (pt 128 96)(pt 128 24)) 84 | (line (pt 112 27)(pt 120 27)) 85 | (line (pt 120 27)(pt 120 39)) 86 | (line (pt 120 39)(pt 112 39)) 87 | (line (pt 112 39)(pt 112 27)) 88 | (line (pt 112 34)(pt 114 36)) 89 | (line (pt 114 36)(pt 112 38)) 90 | (line (pt 98 36)(pt 112 36)) 91 | (line (pt 120 32)(pt 128 32)(line_width 3)) 92 | (line (pt 112 43)(pt 120 43)) 93 | (line (pt 120 43)(pt 120 55)) 94 | (line (pt 120 55)(pt 112 55)) 95 | (line (pt 112 55)(pt 112 43)) 96 | (line (pt 112 50)(pt 114 52)) 97 | (line (pt 114 52)(pt 112 54)) 98 | (line (pt 98 52)(pt 112 52)) 99 | (line (pt 120 48)(pt 128 48)(line_width 3)) 100 | (line (pt 112 59)(pt 120 59)) 101 | (line (pt 120 59)(pt 120 71)) 102 | (line (pt 120 71)(pt 112 71)) 103 | (line (pt 112 71)(pt 112 59)) 104 | (line (pt 112 66)(pt 114 68)) 105 | (line (pt 114 68)(pt 112 70)) 106 | (line (pt 98 68)(pt 112 68)) 107 | (line (pt 120 64)(pt 128 64)) 108 | (line (pt 112 83)(pt 120 83)) 109 | (line (pt 120 83)(pt 120 95)) 110 | (line (pt 120 95)(pt 112 95)) 111 | (line (pt 112 95)(pt 112 83)) 112 | (line (pt 112 90)(pt 114 92)) 113 | (line (pt 114 92)(pt 112 94)) 114 | (line (pt 104 92)(pt 112 92)) 115 | (line (pt 120 88)(pt 128 88)(line_width 3)) 116 | (line (pt 98 36)(pt 98 113)) 117 | (line (pt 104 92)(pt 104 129)) 118 | (line (pt 0 0)(pt 257 0)) 119 | (line (pt 257 0)(pt 257 154)) 120 | (line (pt 0 154)(pt 257 154)) 121 | (line (pt 0 0)(pt 0 154)) 122 | (line (pt 0 0)(pt 0 0)) 123 | (line (pt 0 0)(pt 0 0)) 124 | (line (pt 0 0)(pt 0 0)) 125 | (line (pt 0 0)(pt 0 0)) 126 | ) 127 | ) 128 | -------------------------------------------------------------------------------- /hdmi_display/ram_buffer.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "RAM: 2-PORT" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "ram_buffer.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "ram_buffer.bsf"] 6 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "ram_buffer_inst.v"] 7 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "ram_buffer_bb.v"] 8 | -------------------------------------------------------------------------------- /hdmi_display/ram_buffer_inst.v: -------------------------------------------------------------------------------- 1 | ram_buffer ram_buffer_inst ( 2 | .data ( data_sig ), 3 | .rdaddress ( rdaddress_sig ), 4 | .rdclock ( rdclock_sig ), 5 | .wraddress ( wraddress_sig ), 6 | .wrclock ( wrclock_sig ), 7 | .wren ( wren_sig ), 8 | .q ( q_sig ) 9 | ); 10 | -------------------------------------------------------------------------------- /hdmi_display/rom_font.bsf: -------------------------------------------------------------------------------- 1 | /* 2 | WARNING: Do NOT edit the input and output ports in this file in a text 3 | editor if you plan to continue editing the block that represents it in 4 | the Block Editor! File corruption is VERY likely to occur. 5 | */ 6 | /* 7 | Copyright (C) 2020 Intel Corporation. All rights reserved. 8 | Your use of Intel Corporation's design tools, logic functions 9 | and other software and tools, and any partner logic 10 | functions, and any output files from any of the foregoing 11 | (including device programming or simulation files), and any 12 | associated documentation or information are expressly subject 13 | to the terms and conditions of the Intel Program License 14 | Subscription Agreement, the Intel Quartus Prime License Agreement, 15 | the Intel FPGA IP License Agreement, or other applicable license 16 | agreement, including, without limitation, that your use is for 17 | the sole purpose of programming logic devices manufactured by 18 | Intel and sold by Intel or its authorized distributors. Please 19 | refer to the applicable agreement for further details, at 20 | https://fpgasoftware.intel.com/eula. 21 | */ 22 | (header "symbol" (version "1.2")) 23 | (symbol 24 | (rect 0 0 216 128) 25 | (text "rom_font" (rect 83 0 142 16)(font "Arial" (font_size 10))) 26 | (text "inst" (rect 8 112 25 124)(font "Arial" )) 27 | (port 28 | (pt 0 32) 29 | (input) 30 | (text "address[11..0]" (rect 0 0 81 14)(font "Arial" (font_size 8))) 31 | (text "address[11..0]" (rect 4 18 71 31)(font "Arial" (font_size 8))) 32 | (line (pt 0 32)(pt 88 32)(line_width 3)) 33 | ) 34 | (port 35 | (pt 0 112) 36 | (input) 37 | (text "clock" (rect 0 0 29 14)(font "Arial" (font_size 8))) 38 | (text "clock" (rect 4 98 27 111)(font "Arial" (font_size 8))) 39 | (line (pt 0 112)(pt 80 112)) 40 | ) 41 | (port 42 | (pt 216 32) 43 | (output) 44 | (text "q[7..0]" (rect 0 0 35 14)(font "Arial" (font_size 8))) 45 | (text "q[7..0]" (rect 183 18 211 31)(font "Arial" (font_size 8))) 46 | (line (pt 216 32)(pt 136 32)(line_width 3)) 47 | ) 48 | (drawing 49 | (text "8 bits" (rect 109 23 191 153)(font "Arial" )(vertical)) 50 | (text "4096 words" (rect 120 12 214 177)(font "Arial" )(vertical)) 51 | (text "Block type: M9K" (rect 48 114 164 239)(font "Arial" )) 52 | (line (pt 104 24)(pt 136 24)) 53 | (line (pt 136 24)(pt 136 96)) 54 | (line (pt 136 96)(pt 104 96)) 55 | (line (pt 104 96)(pt 104 24)) 56 | (line (pt 118 58)(pt 123 63)) 57 | (line (pt 118 62)(pt 123 57)) 58 | (line (pt 88 27)(pt 96 27)) 59 | (line (pt 96 27)(pt 96 39)) 60 | (line (pt 96 39)(pt 88 39)) 61 | (line (pt 88 39)(pt 88 27)) 62 | (line (pt 88 34)(pt 90 36)) 63 | (line (pt 90 36)(pt 88 38)) 64 | (line (pt 80 36)(pt 88 36)) 65 | (line (pt 96 32)(pt 104 32)(line_width 3)) 66 | (line (pt 80 112)(pt 80 36)) 67 | (line (pt 0 0)(pt 217 0)) 68 | (line (pt 217 0)(pt 217 130)) 69 | (line (pt 0 130)(pt 217 130)) 70 | (line (pt 0 0)(pt 0 130)) 71 | (line (pt 0 0)(pt 0 0)) 72 | (line (pt 0 0)(pt 0 0)) 73 | (line (pt 0 0)(pt 0 0)) 74 | (line (pt 0 0)(pt 0 0)) 75 | ) 76 | ) 77 | -------------------------------------------------------------------------------- /hdmi_display/rom_font.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "ROM: 1-PORT" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "rom_font.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "rom_font.bsf"] 6 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "rom_font_inst.v"] 7 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "rom_font_bb.v"] 8 | -------------------------------------------------------------------------------- /hdmi_display/rom_font_inst.v: -------------------------------------------------------------------------------- 1 | rom_font rom_font_inst ( 2 | .address ( address_sig ), 3 | .clock ( clock_sig ), 4 | .q ( q_sig ) 5 | ); 6 | -------------------------------------------------------------------------------- /hdmi_display/vga_ctrl.v: -------------------------------------------------------------------------------- 1 | /*********************************************************************************************** 2 | 3 | VGA Timings: http://martin.hinner.info/vga/timing.html 4 | 5 | ┌────────────────┬───────────┬────────────────────────────────┬────────────────────────────────┐ 6 | │ │ │ H Sync │ V Sync │ 7 | │ Display Mode │ Clock/MHz ├───────┬───────┬────────┬───────┼───────┬───────┬────────┬───────┤ 8 | │ │ │ Sync │ Back │ Active │ Front │ Sync │ Back │ Active │ Front │ 9 | │ │ │ Pulse │ Porch │ Video │ Porch │ Pulse │ Porch │ Video │ Porch │ 10 | ├────────────────┼───────────┼───────┼───────┼────────┼───────┼───────┼───────┼────────┼───────┤ 11 | │ 640 x 480 @ 60 │ 25.175 │ 96 │ 48 │ 640 │ 16 │ 2 │ 33 │ 480 │ 10 │ 12 | └────────────────┴───────────┴───────┴───────┴────────┴───────┴───────┴───────┴────────┴───────┘ 13 | 14 | ***********************************************************************************************/ 15 | 16 | module vga_ctrl #( 17 | parameter PIX_REQ_OFFSET = 1, // default to 1 18 | parameter RGB_WIDTH = 16 // 16 = RGB-565, 24 = RGB-888 19 | ) 20 | ( 21 | input wire clk, 22 | input wire rst_n, 23 | input wire [RGB_WIDTH-1:0] in_rgb, 24 | 25 | output wire hsync, 26 | output wire vsync, 27 | output wire pix_data_req, 28 | output [9:0] pix_x, 29 | output [9:0] pix_y, 30 | output pix_valid, 31 | output wire [RGB_WIDTH-1:0] out_rgb 32 | ); 33 | 34 | `define DATA_0 10'd0 35 | 36 | parameter H_SYNC = 10'd96, 37 | H_BACK = 10'd48, 38 | H_SIZE = 10'd640, 39 | H_FRONT = 10'd16, 40 | H_TOTAL = H_SYNC + H_BACK + H_SIZE + H_FRONT, // 800 41 | V_SYNC = 10'd2, 42 | V_BACK = 10'd33, 43 | V_SIZE = 10'd480, 44 | V_FRONT = 10'd10, 45 | V_TOTAL = V_SYNC + V_BACK + V_SIZE + V_FRONT; // 525 46 | 47 | // 0 ~ 799 48 | reg [9:0] cnt_h; 49 | 50 | // 0 ~ 524 51 | reg [9:0] cnt_v; 52 | 53 | always @ (posedge clk or negedge rst_n) begin 54 | if (! rst_n) 55 | cnt_h <= `DATA_0; 56 | else if (cnt_h == H_TOTAL - 1) 57 | cnt_h <= `DATA_0; 58 | else 59 | cnt_h <= cnt_h + 1; 60 | end 61 | 62 | always @ (posedge clk or negedge rst_n) begin 63 | if (! rst_n) 64 | cnt_v <= `DATA_0; 65 | else begin 66 | if (cnt_h == H_TOTAL - 1) begin 67 | if (cnt_v == V_TOTAL - 1) 68 | cnt_v <= `DATA_0; 69 | else 70 | cnt_v <= cnt_v + 1; 71 | end else begin 72 | cnt_v <= cnt_v; 73 | end 74 | end 75 | end 76 | 77 | assign pix_valid = rst_n 78 | && (cnt_h >= (H_SYNC + H_BACK)) 79 | && (cnt_h < (H_SYNC + H_BACK + H_SIZE)) 80 | && (cnt_v >= (V_SYNC + V_BACK)) 81 | && (cnt_v < (V_SYNC + V_BACK + V_SIZE)) 82 | ? 1'b1 : 1'b0; 83 | 84 | assign pix_data_req = rst_n 85 | && (cnt_h >= (H_SYNC + H_BACK - PIX_REQ_OFFSET)) 86 | && (cnt_h < (H_SYNC + H_BACK + H_SIZE - PIX_REQ_OFFSET)) 87 | && (cnt_v >= (V_SYNC + V_BACK)) 88 | && (cnt_v < (V_SYNC + V_BACK + V_SIZE)) 89 | ? 1'b1 : 1'b0; 90 | 91 | assign pix_x = pix_data_req == 1'b1 ? (cnt_h - (H_SYNC + H_BACK - PIX_REQ_OFFSET)) : `DATA_0; 92 | assign pix_y = pix_data_req == 1'b1 ? (cnt_v - (V_SYNC + V_BACK)) : `DATA_0; 93 | 94 | assign hsync = cnt_h < H_SYNC ? 1'b1 : 1'b0; 95 | 96 | assign vsync = cnt_v < V_SYNC ? 1'b1 : 1'b0; 97 | 98 | assign out_rgb = pix_valid == 1'b1 ? in_rgb : {RGB_WIDTH{1'b0}}; 99 | 100 | endmodule 101 | -------------------------------------------------------------------------------- /key_filter/digital_tube_data.v: -------------------------------------------------------------------------------- 1 | // 6位数码管输入数据 2 | 3 | module digital_tube_data 4 | ( 5 | input clk, 6 | input rst_n, 7 | input [47:0] data, // 输入数据 8 x 6 = 48 bit 8 | output reg [7:0] seg, 9 | output reg [5:0] sel 10 | ); 11 | 12 | reg [15:0] cnt16; // 0 ~ 65535 13 | 14 | always @ (posedge clk or negedge rst_n) begin 15 | if (! rst_n) begin 16 | cnt16 <= 16'b0; 17 | seg <= 8'b0000_0000; 18 | sel <= 6'b000_001; 19 | end else begin 20 | cnt16 <= cnt16 + 16'b1; 21 | if (cnt16 == 16'hffff) begin 22 | case (sel) 23 | 6'b000_001: begin 24 | sel <= 6'b000_010; 25 | seg <= data[15:8]; 26 | end 27 | 6'b000_010: begin 28 | sel <= 6'b000_100; 29 | seg <= data[23:16]; 30 | end 31 | 6'b000_100: begin 32 | sel <= 6'b001_000; 33 | seg <= data[31:24]; 34 | end 35 | 6'b001_000: begin 36 | sel <= 6'b010_000; 37 | seg <= data[39:32]; 38 | end 39 | 6'b010_000: begin 40 | sel <= 6'b100_000; 41 | seg <= data[47:40]; 42 | end 43 | 6'b100_000: begin 44 | sel <= 6'b000_001; 45 | seg <= data[7:0]; 46 | end 47 | default: begin 48 | sel <= 6'b000_001; 49 | seg <= data[7:0]; 50 | end 51 | endcase 52 | end 53 | end 54 | end 55 | 56 | endmodule 57 | -------------------------------------------------------------------------------- /key_filter/digital_tube_display.v: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | Digital Tube Display 数码管动态显示 4 | 5 | 位选信号 a ~ h: 0点亮 6 | 7 | ┌───────────────┐ 8 | │ a │ 9 | ├───┬───────┬───┤ 10 | │ │ │ │ 11 | │ f │ │ b │ 12 | │ │ │ │ 13 | ├───┴───────┴───┤ 14 | │ g │ 15 | ├───┬───────┬───┤ 16 | │ │ │ │ 17 | │ e │ │ c │ 18 | │ │ │ │ 19 | ├───┴───────┴───┤ ┌───┐ 20 | │ d │ │ h │ 21 | └───────────────┘ └───┘ 22 | 23 | ******************************************************************************/ 24 | 25 | module digital_tube_display 26 | ( 27 | input clk, 28 | input rst_n, 29 | input [7:0] seg, // 数码管位选信号 30 | input [5:0] sel, // 数码管段选信号 31 | output reg shcp, // 移位寄存器时钟 32 | output reg stcp, // 存储寄存器时钟 33 | output reg ds, // 串行数据输出至 74HC595 芯片 34 | output oe // 始能信号 =0 有效 35 | ); 36 | 37 | reg [1:0] cnt; 38 | reg [3:0] cnt_bit; 39 | 40 | wire [15:0] data; 41 | 42 | assign data = {seg[7:0], sel[5:0]}; 43 | 44 | always @ (posedge clk) begin 45 | if (! rst_n) begin 46 | cnt <= 2'b0; 47 | cnt_bit <= 4'b0; 48 | ds <= 1'b0; 49 | shcp <= 1'b0; 50 | stcp <= 1'b0; 51 | end else begin 52 | cnt <= cnt + 2'h1; 53 | 54 | if (cnt == 2'h3) begin 55 | if (cnt_bit == 4'hd) 56 | cnt_bit <= 4'h0; 57 | else 58 | cnt_bit <= cnt_bit + 4'h1; 59 | end else 60 | cnt_bit <= cnt_bit; 61 | 62 | // output ds: 63 | if (cnt == 2'b0) 64 | ds <= data[cnt_bit]; 65 | else 66 | ds <= ds; 67 | 68 | // output shcp: 69 | if (cnt == 2'h2) 70 | shcp <= 1'b1; 71 | else if (cnt == 2'h0) 72 | shcp <= 1'b0; 73 | else 74 | shcp <= shcp; 75 | 76 | // output stcp: 77 | if (cnt == 2'h0 && cnt_bit == 4'h0) 78 | stcp <= 1'b1; 79 | else if (cnt == 2'h2 && cnt_bit == 4'h0) 80 | stcp <= 1'b0; 81 | else 82 | stcp <= stcp; 83 | end 84 | end 85 | 86 | assign oe = 1'b0; 87 | 88 | endmodule 89 | -------------------------------------------------------------------------------- /key_filter/key_filter.csv: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Intel Corporation. All rights reserved. 2 | # Your use of Intel Corporation's design tools, logic functions 3 | # and other software and tools, and any partner logic 4 | # functions, and any output files from any of the foregoing 5 | # (including device programming or simulation files), and any 6 | # associated documentation or information are expressly subject 7 | # to the terms and conditions of the Intel Program License 8 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 9 | # the Intel FPGA IP License Agreement, or other applicable license 10 | # agreement, including, without limitation, that your use is for 11 | # the sole purpose of programming logic devices manufactured by 12 | # Intel and sold by Intel or its authorized distributors. Please 13 | # refer to the applicable agreement for further details, at 14 | # https://fpgasoftware.intel.com/eula. 15 | 16 | # Quartus Prime Version 20.1.1 Build 720 11/11/2020 SJ Lite Edition 17 | # File: C:\Users\Michael\Git\GitHub\learn-verilog\key_filter\key_filter.csv 18 | # Generated on: Sun Sep 04 12:14:19 2022 19 | 20 | # Note: The column header names should not be changed if you wish to import this .csv file into the Quartus Prime software. 21 | 22 | To,Direction,Location,I/O Bank,VREF Group,Fitter Location,I/O Standard,Reserved,Current Strength,Slew Rate,Differential Pair,Strict Preservation 23 | clk,Input,PIN_E1,1,B1_N0,PIN_E1,,,,,, 24 | ds,Output,PIN_R1,2,B2_N0,PIN_B6,,,,,, 25 | key_in0,Input,PIN_M2,2,B2_N0,PIN_A4,,,,,, 26 | key_in1,Input,PIN_M1,2,B2_N0,PIN_F2,,,,,, 27 | key_in2,Input,PIN_E15,6,B6_N0,PIN_G1,,,,,, 28 | key_in3,Input,PIN_E16,6,B6_N0,PIN_D8,,,,,, 29 | oe,Output,PIN_L11,4,B4_N0,PIN_F7,,,,,, 30 | rst_n,Input,PIN_M15,5,B5_N0,PIN_M2,,,,,, 31 | shcp,Output,PIN_B1,1,B1_N0,PIN_G2,,,,,, 32 | stcp,Output,PIN_K9,4,B4_N0,PIN_C6,,,,,, 33 | -------------------------------------------------------------------------------- /key_filter/key_filter.v: -------------------------------------------------------------------------------- 1 | // 按键消抖 2 | 3 | module key_filter 4 | #( 5 | parameter SYS_CLK = 50_000_000, // default to 50 MHz 6 | parameter FILTER_TIME = 50 // 毫秒, default to 50 ms 7 | ) 8 | ( 9 | input clk, 10 | input rst_n, 11 | input key_in, 12 | output reg key_out 13 | ); 14 | 15 | // 根据时钟频率计算指定时间内计数器最大值: 16 | localparam 17 | CLK_TIME = 1_000_000_000 / SYS_CLK, // 一个时钟周期的耗时ns 18 | CLK_MAX = FILTER_TIME * 1_000_000 / CLK_TIME, // 计数器最大值 19 | CNT_WIDTH = $clog2(CLK_MAX + 1); // 计数器位宽 20 | 21 | localparam [CNT_WIDTH-1:0] CNT_0 = 0; 22 | localparam [CNT_WIDTH-1:0] CNT_MAX = CLK_MAX; 23 | 24 | reg [CNT_WIDTH-1:0] cnt; 25 | 26 | always @ (posedge clk or negedge rst_n) begin 27 | if (! rst_n) begin 28 | cnt <= CNT_0; 29 | end else begin 30 | if (key_in == 1'b1) begin 31 | // key unpressed, keep 0: 32 | cnt <= CNT_0; 33 | end else begin 34 | // key pressed, cnt = 0, 1, 2, ... , MAX-1, MAX, MAX, ... 计数到最大值后保持 35 | cnt <= (cnt == CNT_MAX) ? CLK_MAX : cnt + 1; 36 | end 37 | end 38 | end 39 | 40 | always @ (posedge clk or negedge rst_n) begin 41 | if (! rst_n) begin 42 | key_out <= 1'b1; 43 | end else begin 44 | // key out is triggered at MAX-1: 45 | key_out <= (cnt == CNT_MAX - 1) ? 1'b0 : 1'b1; 46 | end 47 | end 48 | endmodule 49 | -------------------------------------------------------------------------------- /key_filter/tb_key_filter.v: -------------------------------------------------------------------------------- 1 | `timescale 1ms/1ms 2 | 3 | module tb_key_filter (); 4 | 5 | reg clk; 6 | reg rst_n; 7 | reg key_in; 8 | wire key_out; 9 | 10 | key_filter #( 11 | .SYS_CLK (500), // 500 Hz 12 | .FILTER_TIME (20) // 20 ms 13 | ) 14 | component( 15 | .clk (clk), 16 | .rst_n (rst_n), 17 | .key_in (key_in), 18 | .key_out (key_out) 19 | ); 20 | 21 | initial begin 22 | clk = 1'b1; 23 | rst_n = 1'b0; 24 | #15 25 | rst_n = 1'b1; 26 | #2 27 | key_in = 1'b0; 28 | #4 29 | key_in = 1'b1; 30 | #4 31 | key_in = 1'b0; 32 | #40 33 | key_in = 1'b1; 34 | #5 35 | key_in = 1'b0; 36 | #4 37 | key_in = 1'b1; 38 | #5 39 | key_in = 1'b0; 40 | #50 41 | key_in = 1'b1; 42 | #3 43 | key_in = 1'b0; 44 | #4 45 | key_in = 1'b1; 46 | #5 47 | key_in = 1'b0; 48 | #25 49 | key_in = 1'b1; 50 | #10 51 | $finish; 52 | end 53 | 54 | always #1 clk = ~clk; 55 | 56 | initial begin 57 | $dumpfile("tb_key_filter.vcd"); 58 | $dumpvars(0, component); 59 | end 60 | endmodule 61 | -------------------------------------------------------------------------------- /led/led.v: -------------------------------------------------------------------------------- 1 | // LED controlled by keys. 2 | 3 | module led( 4 | input k1, 5 | input k2, 6 | input k3, 7 | input k4, 8 | output[3:0] leds 9 | ); 10 | assign leds[0] = k1; 11 | assign leds[1] = k2; 12 | assign leds[2] = ~k3; 13 | assign leds[3] = ~k4; 14 | endmodule 15 | -------------------------------------------------------------------------------- /ram_ip/init_data.mif: -------------------------------------------------------------------------------- 1 | WIDTH = 16; 2 | DEPTH = 8; 3 | ADDRESS_RADIX = HEX; 4 | DATA_RADIX = HEX; 5 | CONTENT 6 | BEGIN 7 | 0000 : 1001; 8 | 0001 : 0202; 9 | 0002 : 3333; 10 | 0003 : 4404; 11 | 0004 : 0550; 12 | 0005 : 6000; 13 | 0006 : 0007; 14 | 0007 : f00f; 15 | END; -------------------------------------------------------------------------------- /ram_ip/ram_buffer.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "RAM: 2-PORT" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "ram_buffer.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "ram_buffer_inst.v"] 6 | -------------------------------------------------------------------------------- /ram_ip/ram_buffer_inst.v: -------------------------------------------------------------------------------- 1 | ram_buffer ram_buffer_inst ( 2 | .data ( data_sig ), 3 | .rdaddress ( rdaddress_sig ), 4 | .rdclock ( rdclock_sig ), 5 | .wraddress ( wraddress_sig ), 6 | .wrclock ( wrclock_sig ), 7 | .wren ( wren_sig ), 8 | .q ( q_sig ) 9 | ); 10 | -------------------------------------------------------------------------------- /ram_ip/tb_top.v: -------------------------------------------------------------------------------- 1 | `timescale 1ps/1ps 2 | 3 | module tb_top (); 4 | 5 | reg sys_clk; 6 | reg [2:0] addr; 7 | wire [15:0] data; 8 | 9 | top top_inst ( 10 | .sys_clk (sys_clk), 11 | .addr (addr), 12 | .data (data) 13 | ); 14 | 15 | initial begin 16 | sys_clk = 1'b0; 17 | addr = 3'b0; 18 | #5000 19 | $finish; 20 | end 21 | 22 | always #1 sys_clk = ~sys_clk; 23 | always #2 addr = addr + 3'b1; 24 | 25 | endmodule 26 | -------------------------------------------------------------------------------- /ram_ip/top.v: -------------------------------------------------------------------------------- 1 | module top( 2 | input wire sys_clk, 3 | input wire [2:0] addr, 4 | output wire [15:0] data 5 | ); 6 | 7 | ram_buffer ram_buffer_inst ( 8 | .rdclock (sys_clk), 9 | .wrclock (sys_clk), 10 | .data (16'd0), 11 | .rdaddress (addr), 12 | .wraddress (3'd0), 13 | .wren (1'b0), 14 | .q (data) 15 | ); 16 | endmodule 17 | -------------------------------------------------------------------------------- /resources/font/ascii-font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelliao/learn-verilog/8c544c13f889e6e6c83d6abba7746e4c59b54bf1/resources/font/ascii-font.png -------------------------------------------------------------------------------- /resources/font/ascii-font.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelliao/learn-verilog/8c544c13f889e6e6c83d6abba7746e4c59b54bf1/resources/font/ascii-font.psd -------------------------------------------------------------------------------- /resources/font/init-screen.txt: -------------------------------------------------------------------------------- 1 | +------------------------------------------------------------------------------+ 2 | | HELLO, WORLD | 3 | +------------------------------------------------------------------------------+ 4 | | | 5 | | // Copyright (C) liaoxuefeng.com | 6 | | | 7 | | // half adder: | 8 | | | 9 | | module half_adder ( | 10 | | input wire i1, | 11 | | input wire i2, | 12 | | output wire sum, | 13 | | output wire carry | 14 | | ); | 15 | | | 16 | | assign sum = i1 ^ i2; | 17 | | assign carry = i1 & i2; | 18 | | | 19 | | endmodule | 20 | | | 21 | | // ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 | 22 | | // ~!@#$%^&*()_+`-={}[]:;"'<>?,. | 23 | +------------------------------------------------------------------------------+ 24 | | Learn Verilog HDL at https://www.liaoxuefeng.com | 25 | +------------------------------------------------------------------------------+ -------------------------------------------------------------------------------- /resources/script/gen_char_buffer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ' convert text to RAM init data ' 4 | 5 | import argparse 6 | 7 | from mif import gen_mif 8 | 9 | 10 | COLS = 80 11 | ROWS = 25 12 | 13 | # Bg/Fg color, 0 = Black, F = White 14 | BLACK = 0 15 | BLUE = 1 16 | GREEN = 2 17 | CYAN = 3 18 | RED = 4 19 | MAGENTA = 5 20 | BROWN = 6 21 | LIGHT_GRAY = 7 22 | DARK_GRAY = 8 23 | LIGHT_BLUE = 9 24 | LIGHT_GREEN = 10 25 | LIGHT_CYAN = 11 26 | LIGHT_RED = 12 27 | LIGHT_MAGENTA = 13 28 | YELLOW = 14 29 | WHITE = 15 30 | 31 | 32 | def main(): 33 | parser = argparse.ArgumentParser( 34 | description='Generate ascii binary data from text file.') 35 | parser.add_argument('-i', '--input', required=True, type=str, metavar='screen.txt', 36 | help='multi-line text as input file.') 37 | parser.add_argument('-o', '--output', required=True, type=str, metavar='screen.mif', 38 | help='mif binary data as output file.') 39 | args = parser.parse_args() 40 | print(f'input file: {args.input}') 41 | print(f'output file: {args.output}') 42 | with open(args.input, 'r') as f: 43 | lines = f.readlines() 44 | if len(lines) > ROWS: 45 | print(f'Error: too many lines: {lines}') 46 | exit(1) 47 | while len(lines) < ROWS: 48 | lines.append('') 49 | data = b'' 50 | for y, line in enumerate(lines): 51 | data = data + line_to_data(y, line.rstrip()) 52 | mif_str = gen_mif(data, width=16) 53 | 54 | print(f'writing mif...') 55 | with open(args.output, 'w') as f: 56 | f.write(mif_str) 57 | print('ok') 58 | 59 | 60 | def color_of_char(x, y, ch): 61 | bg, fg = BLACK, WHITE 62 | if x in (0, 79) or y in (0, 1, 2, 22, 23, 24): 63 | bg = LIGHT_GRAY 64 | if ch in '+-|': 65 | fg = YELLOW 66 | else: 67 | fg = RED 68 | bgfg = bg * 16 + fg 69 | return bgfg.to_bytes(1, 'big') 70 | 71 | 72 | def line_to_data(y, line): 73 | chars = len(line) 74 | if chars > COLS: 75 | print(f'Error: line {y+1} has too many chars: {chars}') 76 | exit(1) 77 | while len(line) < COLS: 78 | line = line + ' ' 79 | bs = b'' 80 | for x, ch in enumerate(line): 81 | bs = bs + color_of_char(x, y, ch) + ord(ch).to_bytes(1, 'big') 82 | return bs 83 | 84 | 85 | if __name__ == '__main__': 86 | main() 87 | -------------------------------------------------------------------------------- /resources/script/gen_font.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ' convert font png to binary ' 4 | 5 | import argparse 6 | 7 | from PIL import Image 8 | from mif import gen_mif 9 | 10 | CHAR_START = 0 11 | CHAR_WIDTH = 8 12 | CHAR_HEIGHT = 16 13 | 14 | 15 | def main(): 16 | parser = argparse.ArgumentParser( 17 | description='Generate font binary data from png image.') 18 | parser.add_argument('-i', '--input', required=True, type=str, metavar='font.png', 19 | help='png image as input file.') 20 | parser.add_argument('-o', '--output', required=True, type=str, metavar='font.mif', 21 | help='mif binary data as output file.') 22 | args = parser.parse_args() 23 | print(f'input file: {args.input}') 24 | print(f'output file: {args.output}') 25 | 26 | im = Image.open(args.input) 27 | width, height = im.size 28 | if width % CHAR_WIDTH != 0: 29 | print(f'invalid width: {width}') 30 | exit(1) 31 | if height % CHAR_HEIGHT != 0: 32 | print(f'invalid height: {height}') 33 | exit(1) 34 | 35 | w_count = width // CHAR_WIDTH 36 | h_count = height // CHAR_HEIGHT 37 | print(f'characters: {w_count} x {h_count}') 38 | 39 | addr = 0 40 | char = CHAR_START 41 | data = b'' 42 | for row in range(0, h_count): 43 | for col in range(0, w_count): 44 | bs = get_char(im, row, col) 45 | data = data + bs 46 | mif_str = gen_mif(data, width=8, format='bin') 47 | 48 | print(f'writing mif...') 49 | with open(args.output, 'w') as f: 50 | f.write(mif_str) 51 | print('ok') 52 | 53 | 54 | def get_char(im, row, col): 55 | x_start = CHAR_WIDTH * col 56 | x_end = x_start + CHAR_WIDTH 57 | y_start = CHAR_HEIGHT * row 58 | y_end = y_start + CHAR_HEIGHT 59 | bs = b'' 60 | for y in range(y_start, y_end): 61 | s = '' 62 | for x in range(x_start, x_end): 63 | p = im.getpixel((x, y)) 64 | bit = '1' if p > 0 else '0' 65 | s = s + bit 66 | n = int(s, base=2) 67 | b = n.to_bytes(1, 'big') 68 | bs = bs + b 69 | return bs 70 | 71 | 72 | if __name__ == '__main__': 73 | main() 74 | -------------------------------------------------------------------------------- /resources/script/gen_index_color_to_rgb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Full CGA 16-color palette: 4 | # https://en.wikipedia.org/wiki/Color_Graphics_Adapter 5 | 6 | import argparse 7 | 8 | 9 | def main(): 10 | parser = argparse.ArgumentParser( 11 | description='Generate index_color_to_rgb.v source file.') 12 | parser.add_argument('-w', '--width', required=True, type=int, metavar='16 or 24', 13 | help='output rgb mode.') 14 | parser.add_argument('-o', '--output', required=True, type=str, metavar='index_color_to_rgb.v', 15 | help='verilog source as output file.') 16 | args = parser.parse_args() 17 | if (args.width != 16 and args.width != 24): 18 | print('invalid rgb width.') 19 | exit(1) 20 | print(f'using rgb width: {args.width}') 21 | print(f'output file: {args.output}') 22 | 23 | if len(COLORS) != 16: 24 | print('Invalid length of COLORS.') 25 | exit(1) 26 | s = template_1 27 | n = 0 28 | for rgb, name in COLORS: 29 | sr = (rgb & 0xff0000) >> 16 30 | sg = (rgb & 0xff00) >> 8 31 | sb = (rgb & 0xff) 32 | if args.width == 24: 33 | s = s + \ 34 | f' 4\'d{n}: color_rgb = 24\'b{to_bin(sr, 8)}_{to_bin(sg, 8)}_{to_bin(sb, 8)}; // #{to_rgb(rgb)} = {name}\n' 35 | else: 36 | sr = sr * 32 // 256 37 | sg = sg * 64 // 256 38 | sb = sb * 32 // 256 39 | s = s + \ 40 | f' 4\'d{n}: color_rgb = 16\'b{to_bin(sr, 5)}_{to_bin(sg, 6)}_{to_bin(sb, 5)}; // #{to_rgb(rgb)} = {name}\n' 41 | n = n + 1 42 | 43 | s = s + template_2 44 | s = s.replace('WIDTH-1', str(int(args.width) - 1)) 45 | 46 | print(s) 47 | 48 | with open(args.output, 'w') as f: 49 | f.write(s) 50 | 51 | 52 | COLORS = [ 53 | (0x000000, 'black'), 54 | (0x0000AA, 'blue'), 55 | (0x00AA00, 'green'), 56 | (0x00AAAA, 'cyan'), 57 | (0xAA0000, 'red'), 58 | (0xAA00AA, 'magenta'), 59 | (0xAA5500, 'brown'), 60 | (0xAAAAAA, 'light gray'), 61 | (0x555555, 'dark gray'), 62 | (0x5555FF, 'light blue'), 63 | (0x55FF55, 'light green'), 64 | (0x55FFFF, 'light cyan'), 65 | (0xFF5555, 'light red'), 66 | (0xFF55FF, 'light magenta'), 67 | (0xFFFF55, 'yellow'), 68 | (0xFFFFFF, 'white') 69 | ] 70 | 71 | template_1 = '''// VGA 16 Color Palette: 72 | // https://en.wikipedia.org/wiki/Color_Graphics_Adapter 73 | 74 | module index_color_to_rgb ( 75 | input wire [3:0] color_index, 76 | output reg [WIDTH-1:0] color_rgb 77 | ); 78 | always @ (*) begin 79 | case (color_index) 80 | ''' 81 | 82 | template_2 = ''' endcase 83 | end 84 | endmodule 85 | ''' 86 | 87 | 88 | def to_bin(n, width): 89 | s = bin(n)[2:] 90 | while len(s) < width: 91 | s = '0' + s 92 | return s 93 | 94 | 95 | def to_rgb(n): 96 | s = hex(n)[2:] 97 | while len(s) < 6: 98 | s = '0'+s 99 | return s 100 | 101 | 102 | if __name__ == '__main__': 103 | main() 104 | -------------------------------------------------------------------------------- /resources/script/mif.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ' generate MIF from binary data ' 4 | 5 | 6 | def _to_hex(b): 7 | return '%02x' % b 8 | 9 | 10 | def _to_binary(b): 11 | s = bin(b)[2:] 12 | while len(s) < 8: 13 | s = '0' + s 14 | return s 15 | 16 | 17 | def _gen_line(addr, max_addr, bs, format): 18 | n_chars = len(hex(max_addr-1)) - 2 19 | s = f'%0{n_chars}x : ' % addr 20 | for b in bs: 21 | b2s = _to_hex(b) if format == 'hex' else _to_binary(b) 22 | s = s + b2s 23 | s = s + ';' 24 | return s 25 | 26 | 27 | def gen_mif(data, width=8, format='hex'): 28 | ''' 29 | generate MIF as str. 30 | 31 | data: bytes input data. 32 | width: data width in bits, default to 8. 33 | format: data format, default to 'hex'. can be 'hex' or 'bin'. 34 | ''' 35 | if not isinstance(data, bytes): 36 | raise ValueError('data must be bytes.') 37 | if width <= 0 or width % 8 != 0 or width > 256: 38 | raise ValueError('width must be 8, 16, 24, ..., 256.') 39 | n_bytes = width // 8 40 | max_addr = len(data) // n_bytes 41 | if max_addr * n_bytes != len(data): 42 | raise ValueError( 43 | f'invalid data length: {len(data)} and width: {width}') 44 | if format != 'hex' and format != 'bin': 45 | raise ValueError('invalid format: {format}') 46 | 47 | lines = [f'-- total {len(data)} bytes', f'WIDTH = {width};', 48 | f'DEPTH = {max_addr};', 'ADDRESS_RADIX = HEX;', f'DATA_RADIX = {format.upper()};', 'CONTENT', 'BEGIN'] 49 | for addr in range(max_addr): 50 | sub_data = data[addr * n_bytes: (addr+1)*n_bytes] 51 | line = _gen_line(addr, max_addr, sub_data, format) 52 | lines.append(line) 53 | lines.append('END;') 54 | return '\n'.join(lines) 55 | -------------------------------------------------------------------------------- /rs232/rs232.csv: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Intel Corporation. All rights reserved. 2 | # Your use of Intel Corporation's design tools, logic functions 3 | # and other software and tools, and any partner logic 4 | # functions, and any output files from any of the foregoing 5 | # (including device programming or simulation files), and any 6 | # associated documentation or information are expressly subject 7 | # to the terms and conditions of the Intel Program License 8 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 9 | # the Intel FPGA IP License Agreement, or other applicable license 10 | # agreement, including, without limitation, that your use is for 11 | # the sole purpose of programming logic devices manufactured by 12 | # Intel and sold by Intel or its authorized distributors. Please 13 | # refer to the applicable agreement for further details, at 14 | # https://fpgasoftware.intel.com/eula. 15 | 16 | # Quartus Prime Version 20.1.1 Build 720 11/11/2020 SJ Lite Edition 17 | # File: C:\Users\Michael\Git\GitHub\learn-verilog\rs232\rs232.csv 18 | # Generated on: Wed Oct 26 15:26:44 2022 19 | 20 | # Note: The column header names should not be changed if you wish to import this .csv file into the Quartus Prime software. 21 | 22 | To,Direction,Location,I/O Bank,VREF Group,Fitter Location,I/O Standard,Reserved,Current Strength,Slew Rate,Differential Pair,Strict Preservation 23 | clk,Input,PIN_E1,1,B1_N0,PIN_E1,2.5 V,,,,, 24 | in_data,Input,PIN_N6,3,B3_N0,PIN_K8,2.5 V,,,,, 25 | in_led_n,Output,PIN_M6,3,B3_N0,PIN_M6,2.5 V,,,,, 26 | out_data,Output,PIN_N5,3,B3_N0,PIN_M7,2.5 V,,,,, 27 | out_led_n,Output,PIN_L7,3,B3_N0,PIN_L7,2.5 V,,,,, 28 | rst_n,Input,PIN_M15,5,B5_N0,PIN_M15,2.5 V,,,,, 29 | -------------------------------------------------------------------------------- /rs232/tb_top.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module tb_top (); 4 | 5 | reg clk; 6 | reg rst_n; 7 | reg in_data; 8 | 9 | wire [7:0] data; 10 | wire data_en; 11 | 12 | wire out_data; 13 | wire out_en; 14 | 15 | uart_rx rx_component ( 16 | .clk (clk), 17 | .rst_n (rst_n), 18 | .in_data (in_data), 19 | .out_data (data), 20 | .out_en (data_en) 21 | ); 22 | 23 | uart_tx tx_component ( 24 | .clk (clk), 25 | .rst_n (rst_n), 26 | .in_data (data), 27 | .in_en (data_en), 28 | .out_data (out_data), 29 | .out_en (out_en) 30 | ); 31 | 32 | initial begin 33 | clk = 1'b1; 34 | rst_n = 1'b0; 35 | in_data = 8'b1; 36 | #100 37 | rst_n = 1'b1; 38 | #20000 39 | // start 0: 40 | in_data = 1'b0; 41 | #104166 42 | // 01010101: 43 | in_data = 1'b1; 44 | #104166 45 | in_data = 1'b0; 46 | #104166 47 | in_data = 1'b1; 48 | #104166 49 | in_data = 1'b0; 50 | #104166 51 | in_data = 1'b1; 52 | #104166 53 | in_data = 1'b0; 54 | #104166 55 | in_data = 1'b1; 56 | #104166 57 | in_data = 1'b0; 58 | #104166 59 | // parity: 60 | in_data = 1'b1; 61 | #104166 62 | // end 1: 63 | in_data = 1'b1; 64 | #1300000 65 | // next byte: 66 | // start 0: 67 | in_data = 1'b0; 68 | #104166 69 | // 10111100: 70 | in_data = 1'b0; 71 | #104166 72 | in_data = 1'b0; 73 | #104166 74 | in_data = 1'b1; 75 | #104166 76 | in_data = 1'b1; 77 | #104166 78 | in_data = 1'b1; 79 | #104166 80 | in_data = 1'b1; 81 | #104166 82 | in_data = 1'b0; 83 | #104166 84 | in_data = 1'b1; 85 | #104166 86 | // parity: 87 | in_data = 1'b0; 88 | #104166 89 | // end 1: 90 | in_data = 1'b1; 91 | #104166 92 | #1300000 93 | $finish; 94 | end 95 | 96 | always #10 clk = ~clk; 97 | 98 | initial begin 99 | $dumpfile("tb_top.vcd"); 100 | $dumpvars(0, rx_component); 101 | $dumpvars(1, tx_component); 102 | end 103 | endmodule 104 | -------------------------------------------------------------------------------- /rs232/tb_uart_rx.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module tb_uart_rx (); 4 | 5 | reg clk; 6 | reg rst_n; 7 | reg in_data; 8 | wire [7:0] out_data; 9 | wire out_en; 10 | 11 | uart_rx #( 12 | .BAUD (2_500_000), 13 | .SYS_CLK (50_000_000) 14 | ) 15 | component( 16 | .clk (clk), 17 | .rst_n (rst_n), 18 | .in_data (in_data), 19 | .out_data (out_data), 20 | .out_en (out_en) 21 | ); 22 | 23 | reg [7:0] one_byte; 24 | 25 | initial begin 26 | clk = 1'b1; 27 | rst_n = 1'b0; 28 | in_data = 8'b1; 29 | #10 30 | rst_n = 1'b1; 31 | #20 32 | // receive 01010101: 33 | one_byte = 8'b01010101; 34 | // start 0: 35 | in_data = 1'b0; 36 | #40 37 | repeat (8) begin 38 | in_data = one_byte[0]; 39 | one_byte = one_byte >> 1; 40 | #40; 41 | end 42 | // end 1: 43 | in_data = 1'b1; 44 | #40; 45 | // receive: 10111100: 46 | one_byte = 8'b10111100; 47 | // start 0: 48 | in_data = 1'b0; 49 | #40; 50 | repeat (8) begin 51 | in_data = one_byte[0]; 52 | one_byte = one_byte >> 1; 53 | #40; 54 | end 55 | // end 1: 56 | in_data = 1'b1; 57 | #40; 58 | // receive: 00010000: 59 | one_byte = 8'b00010000; 60 | // start 0: 61 | in_data = 1'b0; 62 | #40; 63 | repeat (8) begin 64 | in_data = one_byte[0]; 65 | one_byte = one_byte >> 1; 66 | #40; 67 | end 68 | // end 1: 69 | in_data = 1'b1; 70 | #40; 71 | // receive: 11101111: 72 | one_byte = 8'b11101111; 73 | // start 0: 74 | in_data = 1'b0; 75 | #40; 76 | repeat (8) begin 77 | in_data = one_byte[0]; 78 | one_byte = one_byte >> 1; 79 | #40; 80 | end 81 | // end 1: 82 | in_data = 1'b1; 83 | #40; 84 | #100; 85 | $finish; 86 | end 87 | 88 | always #1 clk = ~clk; 89 | 90 | initial begin 91 | $dumpfile("tb_uart_rx.vcd"); 92 | $dumpvars(0, component); 93 | end 94 | endmodule 95 | -------------------------------------------------------------------------------- /rs232/tb_uart_tx.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module tb_uart_tx (); 4 | 5 | reg clk; 6 | reg rst_n; 7 | reg [7:0] in_data; 8 | reg in_en; 9 | wire out_data; 10 | wire out_en; 11 | 12 | uart_tx #( 13 | .BAUD (5_000_000), 14 | .SYS_CLK (50_000_000) 15 | ) 16 | component( 17 | .clk (clk), 18 | .rst_n (rst_n), 19 | .in_data (in_data), 20 | .in_en (in_en), 21 | .out_data (out_data), 22 | .out_en (out_en) 23 | ); 24 | 25 | initial begin 26 | clk = 1'b1; 27 | rst_n = 1'b0; 28 | in_en = 1'b0; 29 | in_data = 8'b0; 30 | #10; 31 | rst_n = 1'b1; 32 | #10; 33 | in_en = 1'b1; 34 | in_data = 8'b0011_0001; 35 | #2; 36 | in_en = 1'b0; 37 | in_data = 8'b0; 38 | #250; 39 | in_en = 1'b1; 40 | in_data = 8'b1001_0101; 41 | #2; 42 | in_en = 1'b0; 43 | in_data = 8'b0; 44 | #250; 45 | in_en = 1'b1; 46 | in_data = 8'b0001_0000; 47 | #2; 48 | in_en = 1'b0; 49 | in_data = 8'b0; 50 | #250; 51 | in_en = 1'b1; 52 | in_data = 8'b1110_1111; 53 | #2; 54 | in_en = 1'b0; 55 | in_data = 8'b0; 56 | #250; 57 | $finish; 58 | end 59 | 60 | always #1 clk = ~clk; 61 | 62 | initial begin 63 | $dumpfile("tb_uart_tx.vcd"); 64 | $dumpvars(0, component); 65 | end 66 | endmodule 67 | -------------------------------------------------------------------------------- /rs232/top.v: -------------------------------------------------------------------------------- 1 | // receive and send data 2 | // Baud = 9600, 14400, 19200, 38400, 57600, 115200 3 | 4 | module top ( 5 | input clk, 6 | input rst_n, 7 | input in_data, 8 | output out_data, 9 | output in_led_n, 10 | output out_led_n 11 | ); 12 | 13 | wire [7:0] data; 14 | wire data_en; 15 | wire out_en; 16 | 17 | // 接收数据指示灯计数器,>0时点亮LED,=0时熄灭: 18 | reg [23:0] cnt_in; 19 | // 发送数据指示灯计数器,>0时点亮LED,=0时熄灭: 20 | reg [23:0] cnt_out; 21 | 22 | assign in_led_n = cnt_in > 0 ? 1'b0 : 1'b1; 23 | assign out_led_n = cnt_out > 0 ? 1'b0 : 1'b1; 24 | 25 | uart_rx rx_instance ( 26 | .clk (clk), 27 | .rst_n (rst_n), 28 | .in_data (in_data), 29 | .out_data (data), 30 | .out_en (data_en) 31 | ); 32 | 33 | uart_tx tx_instance ( 34 | .clk (clk), 35 | .rst_n (rst_n), 36 | .in_data (data), 37 | .in_en (data_en), 38 | .out_data (out_data), 39 | .out_en (out_en) 40 | ); 41 | 42 | always @ (posedge clk or negedge rst_n) begin 43 | if (rst_n == 1'b0) begin 44 | cnt_in <= 24'd0; 45 | cnt_out <= 24'd0; 46 | end else begin 47 | if (data_en == 1'b1) 48 | cnt_in <= 24'd1; 49 | else if (cnt_in > 0) 50 | cnt_in <= cnt_in + 1'b1; 51 | else 52 | cnt_in <= 24'd0; 53 | 54 | if (out_data == 1'b0) 55 | cnt_out <= 24'd1; 56 | else if (cnt_out > 0) 57 | cnt_out <= cnt_out + 1'b1; 58 | else 59 | cnt_out <= 24'd0; 60 | end 61 | end 62 | 63 | endmodule 64 | -------------------------------------------------------------------------------- /rs232/uart_rx.v: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | 串口接收数据 (8bit, 不带奇偶校验, 停止位1) 4 | 5 | Baud = 9600, 14400, 19200, 38400, 57600, 115200 6 | 7 | 计数器采样点: 在上下沿的中点采样 8 | 9 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 10 | ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ 11 | ───┐ 0 ┌─────┐ 0 0 ┌─────┐ 0 ┌───────────┐ 0 ┌───── 12 | └─────┘ 1 └───────────┘ 1 └─────┘ 1 1 └─────┘ 1 13 | 14 | ******************************************************************************/ 15 | 16 | module uart_rx #( 17 | parameter BAUD = 9600, // 波特率, 默认值 9600 18 | parameter SYS_CLK = 50_000_000 // 时钟频率, 默认值 50MHz 19 | ) 20 | ( 21 | input clk, 22 | input rst_n, 23 | input in_data, // 输入串口数据 24 | output [7:0] out_data, // 输出接收数据 25 | output reg out_en // 输出=1有效 26 | ); 27 | 28 | localparam 29 | MAX = SYS_CLK / BAUD / 2 - 1, // 计数器最大值 30 | WIDTH = $clog2(MAX + 1); // 计数器位宽 31 | 32 | localparam [WIDTH-1:0] CNT_0 = 0; 33 | localparam [WIDTH-1:0] CNT_MAX = MAX; 34 | 35 | localparam 36 | IDLE = 1'b0, 37 | RECEIVING = 1'b1; 38 | 39 | reg status; 40 | reg [WIDTH-1:0] cnt; 41 | reg [4:0] bps_cnt; // count for 0, 1, 2, ..., 15, 16, 17 42 | reg [7:0] data; 43 | reg [2:0] rx_detect; // 延迟两拍采样 44 | 45 | assign out_data = out_en == 1'b1 ? data : 8'd0; 46 | 47 | always @ (posedge clk) begin 48 | rx_detect[0] <= in_data; 49 | rx_detect[1] <= rx_detect[0]; 50 | rx_detect[2] <= rx_detect[1]; 51 | end 52 | 53 | always @ (posedge clk or negedge rst_n) begin 54 | if (rst_n == 1'b0) begin 55 | status <= IDLE; 56 | cnt <= CNT_0; 57 | bps_cnt <= 5'd0; 58 | data <= 8'd0; 59 | out_en <= 1'b0; 60 | end else begin 61 | if (status == IDLE) begin 62 | data <= 8'd0; 63 | out_en <= 1'b0; 64 | cnt <= CNT_0; 65 | if (rx_detect[2:1] == 2'b10) begin 66 | // start receiving: 67 | status <= RECEIVING; 68 | bps_cnt <= 5'd1; 69 | end else begin 70 | // keep IDEL status: 71 | status <= IDLE; 72 | bps_cnt <= 5'd0; 73 | end 74 | end else begin 75 | // receiving data: 76 | if (cnt == CNT_MAX) begin 77 | cnt <= CNT_0; 78 | case (bps_cnt) 79 | 5'd1: begin 80 | // start 0 sample point: 81 | bps_cnt <= bps_cnt + 1'b1; 82 | end 83 | 5'd2, 5'd4, 5'd6, 5'd8, 5'd10, 5'd12, 5'd14, 5'd16, 5'd18: begin 84 | // ignore sampling near at edge: 85 | bps_cnt <= bps_cnt + 1'b1; 86 | end 87 | 5'd3, 5'd5, 5'd7, 5'd9, 5'd11, 5'd13, 5'd15, 5'd17: begin 88 | bps_cnt <= bps_cnt + 1'b1; 89 | data <= { rx_detect[2], data[7:1] }; 90 | end 91 | 5'd19: begin 92 | // end 1 sample point: 93 | bps_cnt <= 5'd0; 94 | status <= IDLE; 95 | data <= data; 96 | out_en <= 1'b1; 97 | end 98 | default: begin 99 | bps_cnt <= 1'b0; 100 | status <= IDLE; 101 | end 102 | endcase 103 | end else begin 104 | cnt <= cnt + 1; 105 | bps_cnt <= bps_cnt; 106 | status <= RECEIVING; 107 | end 108 | end 109 | end 110 | end 111 | 112 | endmodule 113 | -------------------------------------------------------------------------------- /rs232/uart_tx.v: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | 串口发送数据 (8bit, 不带奇偶校验, 停止位1) 4 | 5 | Baud = 9600, 14400, 19200, 38400, 57600, 115200 6 | 7 | 输出波形在计数器计数点变化: 8 | 9 | │ │ │ │ │ │ │ │ │ │ │ 10 | ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ 11 | ───┐ 0 ┌─────┐ 0 0 ┌─────┐ 0 ┌─────┐ 0 0 ┌────── 12 | └─────┘ 1 └───────────┘ 1 └─────┘ 1 └───────────┘ 1 13 | 14 | ******************************************************************************/ 15 | 16 | module uart_tx #( 17 | parameter BAUD = 9600, // 波特率, 默认值 9600 18 | parameter SYS_CLK = 50_000_000 // 时钟频率, 默认值 50MHz 19 | ) 20 | ( 21 | input clk, 22 | input rst_n, 23 | input [7:0] in_data, // 待发送数据 24 | input in_en, // 发送信号=1有效 25 | output reg out_data, // 输出串口数据信号 26 | output out_en // 输出信号=1有效, 0=空闲 27 | ); 28 | localparam 29 | MAX = SYS_CLK / BAUD - 1, // 计数器最大值 30 | WIDTH = $clog2(MAX + 1); // 计数器位宽 31 | 32 | localparam [WIDTH-1:0] CNT_0 = 0; 33 | localparam [WIDTH-1:0] CNT_MAX = MAX; 34 | 35 | localparam 36 | IDLE = 1'b0, 37 | TRANSFER = 1'b1; 38 | 39 | reg status; 40 | reg [3:0] bps_cnt; // count for 0, 1, 2, ..., 7, 8 41 | reg [WIDTH-1:0] cnt; 42 | reg [7:0] data; 43 | 44 | assign out_en = status; 45 | 46 | always @ (posedge clk or negedge rst_n) begin 47 | if (rst_n == 1'b0) begin 48 | status <= IDLE; 49 | bps_cnt <= 4'd0; 50 | cnt <= CNT_0; 51 | data <= 8'b0; 52 | out_data <= 1'b1; 53 | end else begin 54 | if (status == IDLE) begin 55 | if (in_en == 1'b1) begin 56 | // 输入数据有效时准备传输: 57 | status <= TRANSFER; 58 | bps_cnt <= 4'd1; 59 | cnt <= CNT_MAX; 60 | data <= in_data; 61 | out_data <= 1'b1; 62 | end 63 | end else begin 64 | // transfer data: 65 | status <= TRANSFER; 66 | if (cnt == CNT_MAX) begin 67 | cnt <= CNT_0; 68 | case (bps_cnt) 69 | 4'd1: begin 70 | // start 0: 71 | out_data <= 1'b0; 72 | bps_cnt <= bps_cnt + 1'b1; 73 | end 74 | 4'd2: begin 75 | out_data <= data[0]; 76 | bps_cnt <= bps_cnt + 1'b1; 77 | end 78 | 4'd3: begin 79 | out_data <= data[1]; 80 | bps_cnt <= bps_cnt + 1'b1; 81 | end 82 | 4'd4: begin 83 | out_data <= data[2]; 84 | bps_cnt <= bps_cnt + 1'b1; 85 | end 86 | 4'd5: begin 87 | out_data <= data[3]; 88 | bps_cnt <= bps_cnt + 1'b1; 89 | end 90 | 4'd6: begin 91 | out_data <= data[4]; 92 | bps_cnt <= bps_cnt + 1'b1; 93 | end 94 | 4'd7: begin 95 | out_data <= data[5]; 96 | bps_cnt <= bps_cnt + 1'b1; 97 | end 98 | 4'd8: begin 99 | out_data <= data[6]; 100 | bps_cnt <= bps_cnt + 1'b1; 101 | end 102 | 4'd9: begin 103 | out_data <= data[7]; 104 | bps_cnt <= bps_cnt + 1'b1; 105 | end 106 | 4'd10: begin 107 | // end 1: 108 | out_data <= 1'b1; 109 | bps_cnt <= bps_cnt + 1'b1; 110 | status <= TRANSFER; 111 | end 112 | 4'd11: begin 113 | // done: 114 | out_data <= 1'b1; 115 | bps_cnt <= 4'd0; 116 | status <= IDLE; 117 | end 118 | default: begin 119 | out_data <= 1'b1; 120 | bps_cnt <= 4'd0; 121 | status <= IDLE; 122 | end 123 | endcase 124 | end else begin 125 | cnt <= cnt + 1; 126 | end 127 | end 128 | end 129 | end 130 | 131 | endmodule 132 | -------------------------------------------------------------------------------- /sdram/README.md: -------------------------------------------------------------------------------- 1 | # SDRAM 2 | 3 | SDRAM = Synchronized Dynamic RAM 4 | 5 | # Hardware 6 | 7 | Micron MT48LC16M16A2 - 4 Meg x 16 x 4 banks = 256 Mbit = 32 MB 8 | 9 | Refresh count: 8K 10 | Bank addressing: 4 BA[1:0] 11 | Row addressing: 8K A[12:0] 12 | Column addressing: 512 A[8:0] 13 | 14 | # Address Mapping 15 | 16 | A 32-bit address is mapping to BA, ROW and COL: 17 | 18 | ``` 19 | │31 25│ │22 10│9 1│0│ 20 | ├─┬─┬─┬─┬─┬─┬─┼─┬─┼─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬─┬─┬─┬─┬─┬─┬─┼─┤ 21 | └─┴─┴─┴─┴─┴─┴─┼─┴─┼─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┼─┴─┴─┴─┴─┴─┴─┴─┴─┼─┘ 22 | ─▶│BA │◀───────── ROW ─────────▶│◀───── COL ─────▶│ 23 | ``` 24 | -------------------------------------------------------------------------------- /sdram/fifo_async_8bit.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "FIFO" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "fifo_async_8bit.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "fifo_async_8bit_inst.v"] 6 | -------------------------------------------------------------------------------- /sdram/fifo_async_8bit_inst.v: -------------------------------------------------------------------------------- 1 | fifo_async_8bit fifo_async_8bit_inst ( 2 | .data ( data_sig ), 3 | .rdclk ( rdclk_sig ), 4 | .rdreq ( rdreq_sig ), 5 | .wrclk ( wrclk_sig ), 6 | .wrreq ( wrreq_sig ), 7 | .q ( q_sig ), 8 | .rdempty ( rdempty_sig ), 9 | .wrfull ( wrfull_sig ) 10 | ); 11 | -------------------------------------------------------------------------------- /sdram/gen_addr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ' generate address from ba, row, col ' 4 | 5 | BA_WIDTH = 2 6 | ROW_WIDTH = 13 7 | COL_WIDTH = 9 8 | CELL_WIDTH = 16 9 | 10 | DATA_BITS = 32 11 | 12 | 13 | def main(): 14 | ba = input_int('BA', 0, (1 << BA_WIDTH) - 1) 15 | row = input_int('ROW', 0, (1 << ROW_WIDTH) - 1) 16 | col = input_int('COL', 0, (1 << COL_WIDTH) - 1) 17 | if col % 2 == 1: 18 | print('col must be odd.') 19 | exit(1) 20 | data = input_int('DATA', 0, (1 << 32) - 1) 21 | addr = bin_width(ba, BA_WIDTH) + '_' + bin_width(row, ROW_WIDTH) + \ 22 | '_' + bin_width(col, COL_WIDTH) 23 | if CELL_WIDTH > 8: 24 | addr = addr + '_' + bin_width(0, CELL_WIDTH / 8 - 1) 25 | dqm_len = DATA_BITS // 8 26 | 27 | print(f'addr = 32\'b{addr}') 28 | print(f'data = 32\'h{hex_width(data, 8)}') 29 | print(f'dqm = {dqm_len}\'b{"1"*dqm_len}') 30 | 31 | 32 | def bin_width(x, width): 33 | s = bin(x)[2:] 34 | while len(s) < width: 35 | s = '0' + s 36 | return s 37 | 38 | 39 | def hex_width(x, width): 40 | s = hex(x)[2:] 41 | while len(s) < width: 42 | s = '0' + s 43 | return s 44 | 45 | 46 | def input_int(prompt, min, max): 47 | n = 0 48 | s = input(f'{prompt} ({min} ~ {max}): ') 49 | if s.startswith('0x'): 50 | n = int(s[2:], 16) 51 | elif s.startswith('0b'): 52 | n = int(s[2:], 2) 53 | else: 54 | n = int(s) 55 | if n < min or n > max: 56 | print('invalid input.') 57 | exit(1) 58 | return n 59 | 60 | 61 | if __name__ == '__main__': 62 | main() 63 | -------------------------------------------------------------------------------- /sdram/micron-256mb-sdr.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelliao/learn-verilog/8c544c13f889e6e6c83d6abba7746e4c59b54bf1/sdram/micron-256mb-sdr.pdf -------------------------------------------------------------------------------- /sdram/op.v: -------------------------------------------------------------------------------- 1 | // SDRAM read / write by rs232 port. 2 | 3 | `define OP_WRITE 8'hfe 4 | `define OP_READ 8'hfd 5 | -------------------------------------------------------------------------------- /sdram/rx_fsm.v: -------------------------------------------------------------------------------- 1 | // data from rx write to fifo, then read as u64 2 | 3 | `include "op.v" 4 | 5 | module rx_fsm #( 6 | parameter BAUD = 9600, // 波特率, 默认值 9600 7 | parameter SYS_CLK = 50_000_000 // 时钟频率, 默认值 50MHz 8 | ) 9 | ( 10 | input clk_wr, 11 | input clk_rd, 12 | input wr_rst_n, 13 | input rd_rst_n, 14 | input in_rx_data, 15 | input op_ack, 16 | output reg [7:0] op, 17 | output reg [31:0] address, 18 | output reg [31:0] data 19 | ); 20 | // fsm 21 | localparam 22 | IDLE = 2'b00, 23 | FETCH = 2'b01, 24 | READY = 2'b11; 25 | 26 | 27 | reg [1:0] state; 28 | 29 | reg rd_req; 30 | wire wr_full; 31 | wire [7:0] rd_data; 32 | reg [3:0] rd_data_cnt; 33 | reg [63:0] rd_data_cache; 34 | 35 | wire rx_data_en; 36 | wire [7:0] rx_data; 37 | 38 | always @ (posedge clk_rd or negedge rd_rst_n) begin 39 | if (! rd_rst_n) begin 40 | state <= IDLE; 41 | rd_req <= 1'b0; 42 | rd_data_cnt <= 4'b0; 43 | rd_data_cache <= 64'b0; 44 | op <= 8'b0; 45 | end else begin 46 | case (state) 47 | IDLE: begin 48 | if (wr_full) begin 49 | // 在下一个周期读取fifo: 50 | state <= FETCH; 51 | rd_req <= 1'b1; 52 | rd_data_cnt <= 4'd7; 53 | end 54 | end 55 | FETCH: begin 56 | // 读fifo: 57 | if (rd_data_cnt > 0) begin 58 | rd_data_cache[7:0] <= rd_data; 59 | rd_data_cache[63:8] <= rd_data_cache[55:0]; 60 | rd_data_cnt <= rd_data_cnt + 1; 61 | end else begin 62 | rd_req <= 1'b0; 63 | if (rd_data_cache[63:56] == `OP_READ || rd_data_cache[63:56] == `OP_WRITE) begin 64 | op <= rd_data_cache[63:56]; 65 | address <= {8'b0, rd_data_cache[55:32]}; 66 | data <= rd_data_cache[31:0]; 67 | state <= READY; 68 | end else begin 69 | state <= IDLE; 70 | end 71 | end 72 | end 73 | READY: begin 74 | if (op_ack) begin 75 | op <= 8'b0; 76 | address <= 32'b0; 77 | data <= 32'b0; 78 | state <= IDLE; 79 | end 80 | end 81 | default: state <= IDLE; 82 | endcase 83 | end 84 | end 85 | 86 | fifo_async_8bit rx_fifo_inst ( 87 | // 写入fifo: 88 | .wrclk (clk_wr), 89 | .wrreq (rx_data_en), 90 | .data (rx_data), 91 | .wrfull (wr_full), 92 | // 读取fifo: 93 | .rdclk (clk_rd), 94 | .rdreq (rd_req), 95 | .q (rd_data) 96 | ); 97 | 98 | uart_rx #( 99 | .BAUD (BAUD), 100 | .SYS_CLK (SYS_CLK) 101 | ) 102 | uart_rx_inst ( 103 | .clk (clk_wr), 104 | .rst_n (wr_rst_n), 105 | .in_data (in_rx_data), 106 | .out_en (rx_data_en), 107 | .out_data (rx_data) 108 | ); 109 | 110 | endmodule 111 | -------------------------------------------------------------------------------- /sdram/sdr_pll.ppf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /sdram/sdr_pll.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "ALTPLL" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "sdr_pll.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "sdr_pll_inst.v"] 6 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "sdr_pll.ppf"] 7 | -------------------------------------------------------------------------------- /sdram/sdr_pll_inst.v: -------------------------------------------------------------------------------- 1 | sdr_pll sdr_pll_inst ( 2 | .inclk0 ( inclk0_sig ), 3 | .c0 ( c0_sig ), 4 | .c1 ( c1_sig ), 5 | .locked ( locked_sig ) 6 | ); 7 | -------------------------------------------------------------------------------- /sdram/sdram_fsm.v: -------------------------------------------------------------------------------- 1 | // read / write sdram 2 | 3 | `include "op.v" 4 | 5 | module sdram_fsm ( 6 | input clk, 7 | input clk_for_sdr, 8 | input rst_n, 9 | 10 | input [7:0] op, 11 | input [31:0] address, 12 | input [31:0] data, 13 | output op_ack, 14 | output op_data, 15 | 16 | output sdr_clk, 17 | output sdr_cs_n, 18 | output sdr_ras_n, 19 | output sdr_cas_n, 20 | output sdr_we_n, 21 | output [1:0] sdr_ba, 22 | output [12:0] sdr_addr, 23 | output [1:0] sdr_dqm, 24 | inout [15:0] inout_sdr_dq 25 | ); 26 | 27 | localparam 28 | IDLE = 3'b000, 29 | READING = 3'b001, 30 | READ_OK = 3'b011, 31 | WRITING = 3'b100, 32 | WRITE_OK = 3'b101; 33 | 34 | reg [1:0] state; 35 | 36 | reg sdr_ctrl_rd_req; 37 | reg sdr_ctrl_wr_req; 38 | reg [31:0] sdr_ctrl_addr; 39 | reg [31:0] sdr_ctrl_wr_data; 40 | wire [31:0] sdr_ctrl_rd_data; 41 | 42 | wire sig_rd_ack; 43 | wire sig_rd_done; 44 | wire sig_wr_ack; 45 | wire sig_wr_done; 46 | 47 | always @ (posedge clk or negedge rst_n) begin 48 | if (! rst_n) begin 49 | state <= IDLE; 50 | sdr_ctrl_rd_req <= 1'b0; 51 | end else begin 52 | case (state) 53 | IDLE: begin 54 | if (op == `OP_READ) begin 55 | sdr_ctrl_rd_req <= 1'b1; 56 | sdr_ctrl_addr <= address; 57 | state <= READING; 58 | end 59 | if (op == `OP_WRITE) begin 60 | sdr_ctrl_wr_req <= 1'b1; 61 | sdr_ctrl_addr <= address; 62 | sdr_ctrl_wr_data <= data; 63 | state <= WRITING; 64 | end 65 | end 66 | READING: begin 67 | if (sig_rd_ack == 1'b1) begin 68 | sdr_ctrl_rd_req <= 1'b0; 69 | end 70 | if (sig_rd_done == 1'b1) begin 71 | state <= READ_OK; 72 | op_ack <= 1'b1; 73 | op_data <= sdr_ctrl_rd_data; 74 | end 75 | end 76 | READ_OK: begin 77 | state <= IDLE; 78 | op_ack <= 1'b0; 79 | op_data <= 32'b0; 80 | end 81 | WRITING: begin 82 | if (sig_wr_ack == 1'b1) begin 83 | sdr_wr_req <= 1'b0; 84 | end 85 | if (sig_wr_done == 1'b1) begin 86 | state <= WRITE_OK; 87 | op_ack <= 1'b1; 88 | op_data <= 32'b0; 89 | end 90 | end 91 | WRITE_OK: begin 92 | state <= IDLE; 93 | op_ack <= 1'b0; 94 | end 95 | default: state <= IDLE; 96 | endcase 97 | end 98 | end 99 | 100 | sdram_ctrl sdram_ctrl_inst ( 101 | .clk (clk), 102 | .clk_for_sdr (clk_for_sdr), 103 | .rst_n (rst_n), 104 | .in_addr (sdr_ctrl_addr), 105 | .in_rd_req (sdr_ctrl_rd_req), 106 | .out_rd_ack (sig_rd_ack), 107 | .out_rd_data (sdr_rd_data), 108 | .out_rd_done (sig_rd_done), 109 | .in_wr_req (sdr_ctrl_wr_req), 110 | .in_wr_dqm (2'b00), 111 | .in_wr_data (sdr_ctrl_wr_data), 112 | .out_wr_ack (sig_wr_ack), 113 | .out_wr_done (sig_wr_done), 114 | 115 | // connect to sdr: 116 | .sdr_clk (sdr_clk), 117 | .out_wr_dqm (2'b00), 118 | .inout_data (inout_sdr_dq), 119 | .cmd ({sdr_cs_n, sdr_ras_n, sdr_cas_n, sdr_we_n}), 120 | .ba (sdr_ba), 121 | .addr (sdr_addr) 122 | ); 123 | 124 | endmodule 125 | -------------------------------------------------------------------------------- /sdram/tb_rx_fsm.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | 3 | module tb_rx_fsm(); 4 | 5 | reg clk_wr; 6 | reg clk_rd; 7 | reg rst_n; 8 | 9 | initial begin 10 | rst_n = 1'b0; 11 | #25 12 | rst_n = 1'b1; 13 | end 14 | 15 | // 50 MHz clk_wr: 16 | initial begin 17 | clk_wr = 1'b1; 18 | forever begin 19 | #10 clk_wr = ~clk_wr; 20 | end 21 | end 22 | 23 | // 100 MHz clk_rd: 24 | initial begin 25 | clk_rd = 1'b1; 26 | #2 27 | forever begin 28 | #5 clk_rd = ~clk_rd; 29 | end 30 | end 31 | 32 | reg in_rx_data; 33 | reg in_op_ack; 34 | wire [7:0] out_op; 35 | wire [31:0] out_address; 36 | wire [31:0] out_data; 37 | 38 | rx_fsm #( 39 | .BAUD (5_000_000) // 波特率是时钟频率的1/10 40 | ) 41 | component ( 42 | .clk_wr (clk_wr), 43 | .clk_rd (clk_rd), 44 | .wr_rst_n (rst_n), 45 | .rd_rst_n (rst_n), 46 | .in_rx_data (in_rx_data), 47 | .op_ack (in_op_ack), 48 | .op (out_op), 49 | .address (out_address), 50 | .data (out_data) 51 | ); 52 | 53 | initial begin 54 | rx_task(64'hfea1b2c3_6c7d8e9c); 55 | rx_task(64'hfdc9b8a7_10244096); 56 | rx_task(64'hfc123456_abcd0123); // bad op = fc 57 | #10000; 58 | $finish; 59 | end 60 | 61 | task rx_task; 62 | input reg [63:0] rx_task_data; 63 | reg [7:0] one_byte; 64 | begin 65 | in_rx_data = 1'b1; 66 | in_op_ack = 1'b0; 67 | #55; 68 | repeat (8) begin 69 | one_byte = rx_task_data[63:56]; 70 | rx_task_data = rx_task_data << 8; 71 | in_rx_data = 1'b0; // leading bit 0 72 | #200; 73 | repeat (8) begin 74 | in_rx_data = one_byte[0]; 75 | one_byte = one_byte >> 1; 76 | #200; 77 | end 78 | in_rx_data = 1'b1; // end bit 1 79 | #200; 80 | end 81 | #300; 82 | in_op_ack = 1'b1; 83 | #40; 84 | in_op_ack = 1'b0; 85 | #100; 86 | end 87 | endtask 88 | 89 | initial begin 90 | $dumpfile("tb_rx_fsm.vcd"); 91 | $dumpvars(0, component); 92 | end 93 | 94 | endmodule 95 | -------------------------------------------------------------------------------- /sdram/tb_sdram_ctrl.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | 3 | module tb_sdram_ctrl(); 4 | 5 | reg clk_100m; 6 | reg clk_100m_shift; 7 | reg rst_n; 8 | 9 | initial begin 10 | rst_n = 1'b0; 11 | #25 12 | rst_n = 1'b1; 13 | end 14 | 15 | // 100 MHz clk and clk_shift: 16 | initial begin 17 | clk_100m = 1'b1; 18 | forever begin 19 | #5 clk_100m = ~clk_100m; 20 | end 21 | end 22 | 23 | initial begin 24 | clk_100m_shift = 1'b0; 25 | #7 26 | forever begin 27 | #5 clk_100m_shift = ~clk_100m_shift; 28 | end 29 | end 30 | 31 | wire [15:0] sdr_dq; 32 | wire [12:0] sdr_addr; 33 | wire [1:0] sdr_ba; 34 | wire [3:0] sdr_cmd; 35 | wire [1:0] sdr_dqm; 36 | 37 | reg [31:0] in_addr; 38 | 39 | reg in_wr_req; 40 | reg [3:0] in_wr_dqm; 41 | reg [31:0] in_wr_data; 42 | reg in_rd_req; 43 | 44 | initial begin 45 | in_wr_req = 1'b0; 46 | in_wr_data = 31'b0; 47 | in_addr = 31'b0; 48 | in_wr_dqm = 4'b0000; 49 | in_rd_req = 1'b0; 50 | end 51 | 52 | initial begin 53 | #429 54 | // write data 0xa1b2c3d4 to address 32'b10_1111101000000_100000110_0: 55 | // BA = 2, ROW = 8000, COL = 262 56 | in_wr_req = 1'b1; 57 | in_addr = 32'b10_1111101000000_100000110_0; 58 | in_wr_data = 32'ha1b2c3d4; 59 | in_wr_dqm = 4'b0000; 60 | #40 61 | in_wr_req = 1'b0; 62 | end 63 | 64 | initial begin 65 | #489 66 | // write data 0x??e5f6?? to address 32'b10_1111101000000_100000110_0: 67 | // BA = 2, ROW = 8000, COL = 262 68 | in_wr_req = 1'b1; 69 | in_addr = 32'b10_1111101000000_100000110_0; 70 | in_wr_data = 32'h00e5f600; 71 | in_wr_dqm = 4'b1001; 72 | #40 73 | in_wr_req = 1'b0; 74 | end 75 | 76 | initial begin 77 | #568 78 | // read data from address 32'b10_1111101000000_100000110_0: 79 | // BA = 2, ROW = 8000, COL = 262 80 | in_rd_req = 1'b1; 81 | in_addr = 32'b10_1111101000000_100000110_0; 82 | #40 83 | in_rd_req = 1'b0; 84 | end 85 | 86 | initial begin 87 | #956 88 | // read data from address 32'b10_1111101000000_100000110_0: 89 | // BA = 2, ROW = 8000, COL = 262 90 | in_rd_req = 1'b1; 91 | in_addr = 32'b10_1111101000000_100000110_0; 92 | #200 93 | in_rd_req = 1'b0; 94 | end 95 | 96 | sdram_ctrl #( 97 | .SDR_TPOWERUP (200), // speed power up from 200 us to 200 ns 98 | .SDR_INIT_AREF_COUNT (2), // aref x2 when init 99 | .SDR_REFRESH_CYCLE_TIME (6_400_000) // set refresh cycle to 6.4 ms to speed up test 100 | ) 101 | component ( 102 | .clk (clk_100m), 103 | .clk_for_sdr (clk_100m_shift), 104 | .rst_n (rst_n), 105 | 106 | // connect in top: 107 | .in_addr (in_addr), 108 | .in_wr_req (in_wr_req), 109 | .in_wr_data (in_wr_data), 110 | .in_wr_dqm (in_wr_dqm), 111 | .in_rd_req (in_rd_req), 112 | 113 | // connect to SDR: 114 | .out_wr_dqm (sdr_dqm), 115 | .inout_data (sdr_dq), 116 | .cmd (sdr_cmd), 117 | .ba (sdr_ba), 118 | .addr (sdr_addr) 119 | ); 120 | 121 | mt48lc16m16a2 sdram_inst ( 122 | .Dq (sdr_dq), 123 | .Addr (sdr_addr), 124 | .Ba (sdr_ba), 125 | .Clk (clk_100m_shift), 126 | .Cke (1'b1), 127 | .Cs_n (sdr_cmd[3]), 128 | .Ras_n (sdr_cmd[2]), 129 | .Cas_n (sdr_cmd[1]), 130 | .We_n (sdr_cmd[0]), 131 | .Dqm (sdr_dqm) 132 | ); 133 | 134 | initial begin 135 | $dumpfile("tb_sdram_ctrl.vcd"); 136 | $dumpvars(0, component); 137 | $dumpvars(0, sdram_inst); 138 | #3000 139 | $finish; 140 | end 141 | 142 | endmodule 143 | -------------------------------------------------------------------------------- /sdram/tb_tx_fsm.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | 3 | module tb_tx_fsm(); 4 | 5 | reg clk_rd; 6 | reg clk_wr; 7 | reg rst_n; 8 | 9 | initial begin 10 | rst_n = 1'b0; 11 | #25 12 | rst_n = 1'b1; 13 | end 14 | 15 | // 50 MHz clk_rd: 16 | initial begin 17 | clk_rd = 1'b1; 18 | forever begin 19 | #10 clk_rd = ~clk_rd; 20 | end 21 | end 22 | 23 | // 100 MHz clk_wr: 24 | initial begin 25 | clk_wr = 1'b1; 26 | #2 27 | forever begin 28 | #5 clk_wr = ~clk_wr; 29 | end 30 | end 31 | 32 | reg wr_req; 33 | reg [31:0] wr_data; 34 | wire rd_empty; 35 | wire out_tx_data; 36 | wire out_tx_en; 37 | 38 | tx_fsm #( 39 | .BAUD (5_000_000) // 波特率是时钟频率的1/10 40 | ) 41 | component ( 42 | .clk_wr (clk_wr), 43 | .clk_rd (clk_rd), 44 | .wr_rst_n (rst_n), 45 | .rd_rst_n (rst_n), 46 | .wr_req (wr_req), 47 | .wr_data (wr_data), 48 | .rd_empty (rd_empty), 49 | .out_tx_data (out_tx_data), 50 | .out_tx_en (out_tx_en) 51 | ); 52 | 53 | initial begin 54 | tx_send(32'ha1b2c3d4); 55 | tx_send(32'h9f7e5d3c); 56 | $stop; 57 | end 58 | 59 | task tx_send; 60 | input reg [31:0] tx_task_data; 61 | begin 62 | wr_req = 1'b0; 63 | wr_data = tx_task_data; 64 | #55; 65 | wr_req <= 1'b1; 66 | #10; 67 | wr_req <= 1'b0; 68 | #10000; 69 | end 70 | endtask 71 | 72 | initial begin 73 | $dumpfile("tb_tx_fsm.vcd"); 74 | $dumpvars(0, component); 75 | end 76 | 77 | endmodule 78 | -------------------------------------------------------------------------------- /sdram/top.v: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | SDRAM read / write by rs232 port. 4 | 5 | 接收串行数据格式: 6 | 7 | struct { 8 | u8: read = 0xfe, write = 0xfd 9 | u24: extends to 32-bits address (8'b0 + u24) 10 | u32: data 11 | } 12 | 13 | 输出串行数据格式: 14 | 15 | u32: data 16 | 17 | ******************************************************************************/ 18 | 19 | module top ( 20 | input clk, 21 | input rst_n, 22 | input in_rx_data, 23 | input out_tx_data, 24 | output sdr_clk, 25 | output sdr_cs_n, 26 | output sdr_ras_n, 27 | output sdr_cas_n, 28 | output sdr_we_n, 29 | output [1:0] sdr_ba, 30 | output [12:0] sdr_addr, 31 | output [1:0] sdr_dqm, 32 | inout [15:0] inout_sdr_dq 33 | ); 34 | 35 | wire clk_100m; 36 | wire clk_100m_shift; 37 | wire pll_rst_n; 38 | 39 | sdr_pll sdr_pll_inst ( 40 | .inclk0 (clk), 41 | .c0 (clk_100m), 42 | .c1 (clk_100m_shift), 43 | .locked (pll_locked) 44 | ); 45 | 46 | assign pll_rst_n = rst_n & pll_locked; 47 | 48 | wire op_ack; 49 | wire [7:0] op; 50 | wire [31:0] address; 51 | wire [31:0] data; 52 | 53 | rx_fsm rx_fsm_inst ( 54 | .clk_wr (clk), 55 | .clk_rd (clk_100m), 56 | .wr_rst_n (rst_n), 57 | .rd_rst_n (pll_rst_n), 58 | .in_rx_data (in_rx_data), 59 | .op_ack (op_ack), 60 | .op (op), 61 | .address (address), 62 | .data (data) 63 | ); 64 | 65 | 66 | 67 | reg sdr_fifo_wr_en; 68 | 69 | 70 | reg sdr_fifo_rd_en; 71 | wire sdr_fifo_rd_empty; 72 | wire [63:0] sdr_fifo_rd_data; 73 | 74 | 75 | endmodule 76 | -------------------------------------------------------------------------------- /sdram/tx_fsm.v: -------------------------------------------------------------------------------- 1 | // data write to fifo, then read and send 2 | 3 | module tx_fsm #( 4 | parameter BAUD = 9600, // 波特率, 默认值 9600 5 | parameter SYS_CLK = 50_000_000 // 时钟频率, 默认值 50MHz 6 | ) 7 | ( 8 | input clk_wr, 9 | input clk_rd, 10 | input wr_rst_n, 11 | input rd_rst_n, 12 | input wr_req, 13 | input [31:0] wr_data, 14 | output rd_empty, 15 | output out_tx_data, 16 | output out_tx_en 17 | ); 18 | // fsm 19 | localparam 20 | IDLE = 2'b00, 21 | RDREQ = 2'b01, 22 | FETCH = 2'b11, 23 | SEND = 2'b10; 24 | 25 | reg [1:0] state; 26 | reg rd_req; 27 | reg tx_data_en; 28 | wire [7:0] rd_data; 29 | reg [7:0] rd_data_cache; 30 | 31 | always @ (posedge clk_rd or negedge rd_rst_n) begin 32 | if (! rd_rst_n) begin 33 | state <= IDLE; 34 | rd_req <= 1'b0; 35 | rd_data_cache <= 8'b0; 36 | end else begin 37 | case (state) 38 | IDLE: begin 39 | if (! rd_empty && ! out_tx_en) begin 40 | // 在下一个周期请求读取fifo: 41 | state <= RDREQ; 42 | rd_req <= 1'b1; 43 | end 44 | end 45 | RDREQ: begin 46 | // 在下一个周期读取fifo: 47 | rd_req <= 1'b0; 48 | state <= FETCH; 49 | end 50 | FETCH: begin 51 | // 读fifo: 52 | rd_data_cache <= rd_data; 53 | rd_req <= 1'b0; 54 | // 下一个状态发送tx: 55 | tx_data_en <= 1'b1; 56 | state <= SEND; 57 | end 58 | SEND: begin 59 | tx_data_en <= 1'b0; 60 | state <= IDLE; 61 | end 62 | default: state <= IDLE; 63 | endcase 64 | end 65 | end 66 | 67 | reg wr_data_req; 68 | reg [31:0] wr_data_cache; 69 | reg [2:0] wr_data_cnt; 70 | 71 | always @ (posedge clk_wr or negedge wr_rst_n) begin 72 | if (! wr_rst_n) begin 73 | wr_data_req <= 1'b0; 74 | wr_data_cache <= 32'b0; 75 | wr_data_cnt <= 3'b0; 76 | end else begin 77 | if (wr_req) begin 78 | wr_data_cache <= wr_data; 79 | wr_data_cnt <= 3'd5; 80 | wr_data_req <= 1'b1; 81 | end else begin 82 | // 5, 6, 7: 83 | if (wr_data_cnt > 0) begin 84 | wr_data_cache[31:8] <= wr_data_cache[23:0]; 85 | wr_data_cnt <= wr_data_cnt + 1; 86 | end else begin 87 | wr_data_req <= 1'b0; 88 | end 89 | end 90 | end 91 | end 92 | 93 | fifo_async_8bit tx_fifo_inst ( 94 | // 写入fifo: 95 | .wrclk (clk_wr), 96 | .wrreq (wr_data_req), 97 | .data (wr_data_cache[31:24]), 98 | // 读取fifo: 99 | .rdclk (clk_rd), 100 | .rdreq (rd_req), 101 | .q (rd_data), 102 | // fifo状态: 103 | .rdempty (rd_empty), 104 | .wrfull (wr_full) 105 | ); 106 | 107 | uart_tx #( 108 | .BAUD (BAUD), 109 | .SYS_CLK (SYS_CLK) 110 | ) 111 | uart_tx_inst ( 112 | .clk (clk_rd), 113 | .rst_n (rd_rst_n), 114 | .in_data (rd_data_cache), 115 | .in_en (tx_data_en), 116 | .out_en (out_tx_en), 117 | .out_data (out_tx_data) 118 | ); 119 | 120 | endmodule 121 | -------------------------------------------------------------------------------- /sdram/uart_rx.v: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | 串口接收数据 (8bit, 不带奇偶校验, 停止位1) 4 | 5 | Baud = 9600, 14400, 19200, 38400, 57600, 115200 6 | 7 | 计数器采样点: 在上下沿的中点采样 8 | 9 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 10 | ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ 11 | ───┐ 0 ┌─────┐ 0 0 ┌─────┐ 0 ┌───────────┐ 0 ┌───── 12 | └─────┘ 1 └───────────┘ 1 └─────┘ 1 1 └─────┘ 1 13 | 14 | ******************************************************************************/ 15 | 16 | module uart_rx #( 17 | parameter BAUD = 9600, // 波特率, 默认值 9600 18 | parameter SYS_CLK = 50_000_000 // 时钟频率, 默认值 50MHz 19 | ) 20 | ( 21 | input clk, 22 | input rst_n, 23 | input in_data, // 输入串口数据 24 | output [7:0] out_data, // 输出接收数据 25 | output reg out_en // 输出=1有效 26 | ); 27 | 28 | localparam 29 | MAX = SYS_CLK / BAUD / 2 - 1, // 计数器最大值 30 | WIDTH = $clog2(MAX + 1); // 计数器位宽 31 | 32 | localparam [WIDTH-1:0] CNT_0 = 0; 33 | localparam [WIDTH-1:0] CNT_MAX = MAX; 34 | 35 | localparam 36 | IDLE = 1'b0, 37 | RECEIVING = 1'b1; 38 | 39 | reg status; 40 | reg [WIDTH-1:0] cnt; 41 | reg [4:0] bps_cnt; // count for 0, 1, 2, ..., 15, 16, 17 42 | reg [7:0] data; 43 | reg [2:0] rx_detect; // 延迟两拍采样 44 | 45 | assign out_data = out_en == 1'b1 ? data : 8'd0; 46 | 47 | always @ (posedge clk) begin 48 | rx_detect[0] <= in_data; 49 | rx_detect[1] <= rx_detect[0]; 50 | rx_detect[2] <= rx_detect[1]; 51 | end 52 | 53 | always @ (posedge clk or negedge rst_n) begin 54 | if (rst_n == 1'b0) begin 55 | status <= IDLE; 56 | cnt <= CNT_0; 57 | bps_cnt <= 5'd0; 58 | data <= 8'd0; 59 | out_en <= 1'b0; 60 | end else begin 61 | if (status == IDLE) begin 62 | data <= 8'd0; 63 | out_en <= 1'b0; 64 | cnt <= CNT_0; 65 | if (rx_detect[2:1] == 2'b10) begin 66 | // start receiving: 67 | status <= RECEIVING; 68 | bps_cnt <= 5'd1; 69 | end else begin 70 | // keep IDEL status: 71 | status <= IDLE; 72 | bps_cnt <= 5'd0; 73 | end 74 | end else begin 75 | // receiving data: 76 | if (cnt == CNT_MAX) begin 77 | cnt <= CNT_0; 78 | case (bps_cnt) 79 | 5'd1: begin 80 | // start 0 sample point: 81 | bps_cnt <= bps_cnt + 1'b1; 82 | end 83 | 5'd2, 5'd4, 5'd6, 5'd8, 5'd10, 5'd12, 5'd14, 5'd16, 5'd18: begin 84 | // ignore sampling near at edge: 85 | bps_cnt <= bps_cnt + 1'b1; 86 | end 87 | 5'd3, 5'd5, 5'd7, 5'd9, 5'd11, 5'd13, 5'd15, 5'd17: begin 88 | bps_cnt <= bps_cnt + 1'b1; 89 | data <= { rx_detect[2], data[7:1] }; 90 | end 91 | 5'd19: begin 92 | // end 1 sample point: 93 | bps_cnt <= 5'd0; 94 | status <= IDLE; 95 | data <= data; 96 | out_en <= 1'b1; 97 | end 98 | default: begin 99 | bps_cnt <= 1'b0; 100 | status <= IDLE; 101 | end 102 | endcase 103 | end else begin 104 | cnt <= cnt + 1; 105 | bps_cnt <= bps_cnt; 106 | status <= RECEIVING; 107 | end 108 | end 109 | end 110 | end 111 | 112 | endmodule 113 | -------------------------------------------------------------------------------- /sdram/uart_tx.v: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | 3 | 串口发送数据 (8bit, 不带奇偶校验, 停止位1) 4 | 5 | Baud = 9600, 14400, 19200, 38400, 57600, 115200 6 | 7 | 输出波形在计数器计数点变化: 8 | 9 | │ │ │ │ │ │ │ │ │ │ │ 10 | ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ 11 | ───┐ 0 ┌─────┐ 0 0 ┌─────┐ 0 ┌─────┐ 0 0 ┌────── 12 | └─────┘ 1 └───────────┘ 1 └─────┘ 1 └───────────┘ 1 13 | 14 | ******************************************************************************/ 15 | 16 | module uart_tx #( 17 | parameter BAUD = 9600, // 波特率, 默认值 9600 18 | parameter SYS_CLK = 50_000_000 // 时钟频率, 默认值 50MHz 19 | ) 20 | ( 21 | input clk, 22 | input rst_n, 23 | input [7:0] in_data, // 待发送数据 24 | input in_en, // 发送信号=1有效 25 | output reg out_data, // 输出串口数据信号 26 | output out_en // 输出信号=1有效, 0=空闲 27 | ); 28 | localparam 29 | MAX = SYS_CLK / BAUD - 1, // 计数器最大值 30 | WIDTH = $clog2(MAX + 1); // 计数器位宽 31 | 32 | localparam [WIDTH-1:0] CNT_0 = 0; 33 | localparam [WIDTH-1:0] CNT_MAX = MAX; 34 | 35 | localparam 36 | IDLE = 1'b0, 37 | TRANSFER = 1'b1; 38 | 39 | reg status; 40 | reg [3:0] bps_cnt; // count for 0, 1, 2, ..., 7, 8 41 | reg [WIDTH-1:0] cnt; 42 | reg [7:0] data; 43 | 44 | assign out_en = status; 45 | 46 | always @ (posedge clk or negedge rst_n) begin 47 | if (rst_n == 1'b0) begin 48 | status <= IDLE; 49 | bps_cnt <= 4'd0; 50 | cnt <= CNT_0; 51 | data <= 8'b0; 52 | out_data <= 1'b1; 53 | end else begin 54 | if (status == IDLE) begin 55 | if (in_en == 1'b1) begin 56 | // 输入数据有效时准备传输: 57 | status <= TRANSFER; 58 | bps_cnt <= 4'd1; 59 | cnt <= CNT_MAX; 60 | data <= in_data; 61 | out_data <= 1'b1; 62 | end 63 | end else begin 64 | // transfer data: 65 | status <= TRANSFER; 66 | if (cnt == CNT_MAX) begin 67 | cnt <= CNT_0; 68 | case (bps_cnt) 69 | 4'd1: begin 70 | // start 0: 71 | out_data <= 1'b0; 72 | bps_cnt <= bps_cnt + 1'b1; 73 | end 74 | 4'd2: begin 75 | out_data <= data[0]; 76 | bps_cnt <= bps_cnt + 1'b1; 77 | end 78 | 4'd3: begin 79 | out_data <= data[1]; 80 | bps_cnt <= bps_cnt + 1'b1; 81 | end 82 | 4'd4: begin 83 | out_data <= data[2]; 84 | bps_cnt <= bps_cnt + 1'b1; 85 | end 86 | 4'd5: begin 87 | out_data <= data[3]; 88 | bps_cnt <= bps_cnt + 1'b1; 89 | end 90 | 4'd6: begin 91 | out_data <= data[4]; 92 | bps_cnt <= bps_cnt + 1'b1; 93 | end 94 | 4'd7: begin 95 | out_data <= data[5]; 96 | bps_cnt <= bps_cnt + 1'b1; 97 | end 98 | 4'd8: begin 99 | out_data <= data[6]; 100 | bps_cnt <= bps_cnt + 1'b1; 101 | end 102 | 4'd9: begin 103 | out_data <= data[7]; 104 | bps_cnt <= bps_cnt + 1'b1; 105 | end 106 | 4'd10: begin 107 | // end 1: 108 | out_data <= 1'b1; 109 | bps_cnt <= bps_cnt + 1'b1; 110 | status <= TRANSFER; 111 | end 112 | 4'd11: begin 113 | // done: 114 | out_data <= 1'b1; 115 | bps_cnt <= 4'd0; 116 | status <= IDLE; 117 | end 118 | default: begin 119 | out_data <= 1'b1; 120 | bps_cnt <= 4'd0; 121 | status <= IDLE; 122 | end 123 | endcase 124 | end else begin 125 | cnt <= cnt + 1; 126 | end 127 | end 128 | end 129 | end 130 | 131 | endmodule 132 | -------------------------------------------------------------------------------- /timer/convert.v: -------------------------------------------------------------------------------- 1 | // convert 0 ~ f to NUM_0 ~ NUM_F: 2 | 3 | module convert ( 4 | input [3:0] in, 5 | output reg [7:0] out 6 | ); 7 | localparam NUM_0 = 8'b00000011; 8 | localparam NUM_1 = 8'b10011111; 9 | localparam NUM_2 = 8'b00100101; 10 | localparam NUM_3 = 8'b00001101; 11 | localparam NUM_4 = 8'b10011001; 12 | localparam NUM_5 = 8'b01001001; 13 | localparam NUM_6 = 8'b01000001; 14 | localparam NUM_7 = 8'b00011111; 15 | localparam NUM_8 = 8'b00000001; 16 | localparam NUM_9 = 8'b00001001; 17 | localparam NUM_A = 8'b00010001; 18 | localparam NUM_B = 8'b11000001; 19 | localparam NUM_C = 8'b01100011; 20 | localparam NUM_D = 8'b10000101; 21 | localparam NUM_E = 8'b01100001; 22 | localparam NUM_F = 8'b01110001; 23 | 24 | always @ (*) begin 25 | case (in) 26 | 4'h0: out = NUM_0; 27 | 4'h1: out = NUM_1; 28 | 4'h2: out = NUM_2; 29 | 4'h3: out = NUM_3; 30 | 4'h4: out = NUM_4; 31 | 4'h5: out = NUM_5; 32 | 4'h6: out = NUM_6; 33 | 4'h7: out = NUM_7; 34 | 4'h8: out = NUM_8; 35 | 4'h9: out = NUM_9; 36 | 4'ha: out = NUM_A; 37 | 4'hb: out = NUM_B; 38 | 4'hc: out = NUM_C; 39 | 4'hd: out = NUM_D; 40 | 4'he: out = NUM_E; 41 | 4'hf: out = NUM_F; 42 | endcase 43 | end 44 | endmodule 45 | -------------------------------------------------------------------------------- /timer/counter.v: -------------------------------------------------------------------------------- 1 | // counter from 0x000000 ~ 0xffffff 2 | 3 | module counter 4 | #( 5 | parameter CNT_MAX = 'h1000000, // 0 ~ 0xffffff 6 | parameter SYS_CLK = 'd50_000_000 // default to 50MHz 7 | ) 8 | ( 9 | input clk, 10 | input rst_n, 11 | output reg [23:0] cnt 12 | ); 13 | 14 | reg [31:0] inc; 15 | 16 | always @ (posedge clk or negedge rst_n) begin 17 | if (! rst_n) begin 18 | cnt <= 24'b0; 19 | inc <= 32'b0; 20 | end else begin 21 | if (inc == (SYS_CLK - 1)) begin 22 | inc <= 32'b0; 23 | if (cnt == (CNT_MAX -1)) 24 | cnt <= 24'b0; 25 | else 26 | cnt <= cnt + 1; 27 | end else begin 28 | inc <= inc + 1; 29 | end 30 | end 31 | end 32 | 33 | endmodule 34 | -------------------------------------------------------------------------------- /timer/digital_tube_data.v: -------------------------------------------------------------------------------- 1 | // digital tube data 2 | 3 | module digital_tube_data 4 | ( 5 | input clk, 6 | input rst_n, 7 | input [47:0] data, 8 | output reg [7:0] seg, 9 | output reg [5:0] sel 10 | ); 11 | 12 | reg [15:0] cnt16; // 0 ~ 65535 13 | 14 | always @ (posedge clk or negedge rst_n) begin 15 | if (! rst_n) begin 16 | cnt16 <= 16'b0; 17 | seg <= 8'b0000_0000; 18 | sel <= 6'b000_001; 19 | end else begin 20 | cnt16 <= cnt16 + 16'b1; 21 | if (cnt16 == 16'hffff) begin 22 | case (sel) 23 | 6'b000_001: begin 24 | sel <= 6'b000_010; 25 | seg <= data[15:8]; 26 | end 27 | 6'b000_010: begin 28 | sel <= 6'b000_100; 29 | seg <= data[23:16]; 30 | end 31 | 6'b000_100: begin 32 | sel <= 6'b001_000; 33 | seg <= data[31:24]; 34 | end 35 | 6'b001_000: begin 36 | sel <= 6'b010_000; 37 | seg <= data[39:32]; 38 | end 39 | 6'b010_000: begin 40 | sel <= 6'b100_000; 41 | seg <= data[47:40]; 42 | end 43 | 6'b100_000: begin 44 | sel <= 6'b000_001; 45 | seg <= data[7:0]; 46 | end 47 | default: begin 48 | sel <= 6'b000_001; 49 | seg <= data[7:0]; 50 | end 51 | endcase 52 | end 53 | end 54 | end 55 | 56 | endmodule 57 | -------------------------------------------------------------------------------- /timer/digital_tube_display.v: -------------------------------------------------------------------------------- 1 | // digital tube display 2 | 3 | module digital_tube_display 4 | ( 5 | input clk, 6 | input rst_n, 7 | input [7:0] seg, 8 | input [5:0] sel, 9 | output reg shcp, 10 | output reg stcp, 11 | output reg ds, 12 | output oe 13 | ); 14 | 15 | reg [1:0] cnt; 16 | reg [3:0] cnt_bit; 17 | 18 | wire [15:0] data; 19 | 20 | assign data = {seg[7:0], sel[5:0]}; 21 | 22 | always @ (posedge clk) begin 23 | if (! rst_n) 24 | begin 25 | cnt <= 2'b0; 26 | cnt_bit <= 4'b0; 27 | ds <= 1'b0; 28 | shcp <= 1'b0; 29 | stcp <= 1'b0; 30 | end 31 | else 32 | begin 33 | cnt <= cnt + 2'h1; 34 | if (cnt == 2'h3) 35 | begin 36 | if (cnt_bit == 4'hd) 37 | cnt_bit <= 4'h0; 38 | else 39 | cnt_bit <= cnt_bit + 4'h1; 40 | end 41 | else 42 | cnt_bit <= cnt_bit; 43 | // output ds: 44 | if (cnt == 2'b0) 45 | ds <= data[cnt_bit]; 46 | else 47 | ds <= ds; 48 | // output shcp: 49 | if (cnt == 2'h2) 50 | shcp <= 1'b1; 51 | else if (cnt == 2'h0) 52 | shcp <= 1'b0; 53 | else 54 | shcp <= shcp; 55 | // output stcp: 56 | if (cnt == 2'h0 && cnt_bit == 4'h0) 57 | stcp <= 1'b1; 58 | else if (cnt == 2'h2 && cnt_bit == 4'h0) 59 | stcp <= 1'b0; 60 | else 61 | stcp <= stcp; 62 | end 63 | end 64 | 65 | assign oe = 1'b0; 66 | 67 | endmodule 68 | -------------------------------------------------------------------------------- /timer/timer.csv: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Intel Corporation. All rights reserved. 2 | # Your use of Intel Corporation's design tools, logic functions 3 | # and other software and tools, and any partner logic 4 | # functions, and any output files from any of the foregoing 5 | # (including device programming or simulation files), and any 6 | # associated documentation or information are expressly subject 7 | # to the terms and conditions of the Intel Program License 8 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 9 | # the Intel FPGA IP License Agreement, or other applicable license 10 | # agreement, including, without limitation, that your use is for 11 | # the sole purpose of programming logic devices manufactured by 12 | # Intel and sold by Intel or its authorized distributors. Please 13 | # refer to the applicable agreement for further details, at 14 | # https://fpgasoftware.intel.com/eula. 15 | 16 | # Quartus Prime Version 20.1.1 Build 720 11/11/2020 SJ Lite Edition 17 | # File: C:\Users\Michael\Git\GitHub\learn-verilog\timer\timer.csv 18 | # Generated on: Sun Oct 02 19:24:42 2022 19 | 20 | # Note: The column header names should not be changed if you wish to import this .csv file into the Quartus Prime software. 21 | 22 | To,Direction,Location,I/O Bank,VREF Group,Fitter Location,I/O Standard,Reserved,Current Strength,Slew Rate,Differential Pair,Strict Preservation 23 | clk,Input,PIN_E1,1,B1_N0,PIN_E1,,,,,, 24 | ds,Output,PIN_R1,2,B2_N0,PIN_E7,,,,,, 25 | oe,Output,PIN_L11,4,B4_N0,PIN_R16,,,,,, 26 | rst_n,Input,PIN_M15,5,B5_N0,PIN_M2,,,,,, 27 | shcp,Output,PIN_B1,1,B1_N0,PIN_A5,,,,,, 28 | stcp,Output,PIN_K9,4,B4_N0,PIN_E6,,,,,, 29 | -------------------------------------------------------------------------------- /timer/top.v: -------------------------------------------------------------------------------- 1 | // timer 2 | 3 | module top ( 4 | input wire clk, 5 | input wire rst_n, 6 | output wire shcp, 7 | output wire stcp, 8 | output wire ds, 9 | output wire oe 10 | ); 11 | wire [47:0] data; 12 | wire [7:0] seg; 13 | wire [5:0] sel; 14 | wire [23:0] cnt; 15 | 16 | counter #(10000) counter_inst( 17 | .clk (clk), 18 | .rst_n (rst_n), 19 | .cnt (cnt) 20 | ); 21 | 22 | convert convert_0( 23 | .in (cnt[3:0]), 24 | .out (data[7:0]) 25 | ); 26 | 27 | convert convert_1( 28 | .in (cnt[7:4]), 29 | .out (data[15:8]) 30 | ); 31 | 32 | convert convert_2( 33 | .in (cnt[11:8]), 34 | .out (data[23:16]) 35 | ); 36 | 37 | convert convert_3( 38 | .in (cnt[15:12]), 39 | .out (data[31:24]) 40 | ); 41 | 42 | convert convert_4( 43 | .in (cnt[19:16]), 44 | .out (data[39:32]) 45 | ); 46 | 47 | convert convert_5( 48 | .in (cnt[23:20]), 49 | .out (data[47:40]) 50 | ); 51 | 52 | digital_tube_data digital_tube_data_inst ( 53 | .clk (clk), 54 | .rst_n (rst_n), 55 | .data (data), 56 | .seg (seg), 57 | .sel (sel) 58 | ); 59 | 60 | digital_tube_display digital_tube_display_inst ( 61 | .clk (clk), 62 | .rst_n (rst_n), 63 | .seg (seg), 64 | .sel (sel), 65 | .shcp (shcp), 66 | .stcp (stcp), 67 | .ds (ds), 68 | .oe (oe) 69 | ); 70 | 71 | endmodule 72 | -------------------------------------------------------------------------------- /vga_ctrl/pll_vga.ppf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /vga_ctrl/pll_vga.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "ALTPLL" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "pll_vga.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll_vga_inst.v"] 6 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll_vga.ppf"] 7 | -------------------------------------------------------------------------------- /vga_ctrl/pll_vga_inst.v: -------------------------------------------------------------------------------- 1 | pll_vga pll_vga_inst ( 2 | .areset ( areset_sig ), 3 | .inclk0 ( inclk0_sig ), 4 | .c0 ( c0_sig ), 5 | .locked ( locked_sig ) 6 | ); 7 | -------------------------------------------------------------------------------- /vga_ctrl/tb_top.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module tb_top (); 4 | 5 | reg clk; 6 | reg rst_n; 7 | wire pll_locked; 8 | wire hsync; 9 | wire vsync; 10 | wire [15:0] out_rgb; 11 | 12 | pll_vga pll_vga_inst( 13 | .areset (~rst_n), 14 | .inclk0 (clk), 15 | .c0 (vga_clk), 16 | .locked (pll_locked) 17 | ); 18 | 19 | vga_ctrl vga_ctrl_inst( 20 | .clk(vga_clk), 21 | .rst_n(rst_n & pll_locked), 22 | .in_rgb(16'hffff), 23 | 24 | .hsync (hsync), 25 | .vsync (vsync), 26 | .out_rgb(out_rgb) 27 | ); 28 | 29 | initial begin 30 | clk = 1'b1; 31 | rst_n = 1'b0; 32 | #10 33 | rst_n = 1'b1; 34 | #5000000 35 | $finish; 36 | end 37 | 38 | always #1 clk = ~clk; 39 | 40 | endmodule 41 | -------------------------------------------------------------------------------- /vga_ctrl/tb_vga_ctrl.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module tb_vga_ctrl (); 4 | 5 | reg clk; 6 | reg rst_n; 7 | reg [15:0] in_rgb; 8 | 9 | vga_ctrl component( 10 | .clk(clk), 11 | .rst_n(rst_n), 12 | .in_rgb(in_rgb) 13 | ); 14 | 15 | initial begin 16 | clk = 1'b1; 17 | rst_n = 1'b0; 18 | in_rgb = 15'b0; 19 | #10 20 | rst_n = 1'b1; 21 | #5000000 22 | $finish; 23 | end 24 | 25 | always #1 clk = ~clk; 26 | 27 | always #16 in_rgb = in_rgb + 1'b1; 28 | 29 | initial begin 30 | $dumpfile("tb_vga_ctrl.vcd"); 31 | $dumpvars(0, component); 32 | end 33 | endmodule 34 | -------------------------------------------------------------------------------- /vga_ctrl/top.v: -------------------------------------------------------------------------------- 1 | module top( 2 | input wire clk, 3 | input wire rst_n, 4 | output wire hsync, 5 | output wire vsync, 6 | output wire [15:0] rgb 7 | ); 8 | wire vga_clk; 9 | wire pll_locked; 10 | wire [15:0] pix_data; 11 | wire [9:0] pix_x; 12 | wire [9:0] pix_y; 13 | 14 | pll_vga pll_vga_inst ( 15 | .areset (~rst_n), 16 | .inclk0 (clk), 17 | .c0 (vga_clk), 18 | .locked (pll_locked) 19 | ); 20 | 21 | vga_data vga_data_inst ( 22 | .clk (vga_clk), 23 | .rst_n (rst_n & pll_locked), 24 | .pix_x (pix_x), 25 | .pix_y (pix_y), 26 | .pix_rgb (pix_data) 27 | ); 28 | 29 | vga_ctrl vga_ctrl_inst ( 30 | .clk (vga_clk), 31 | .rst_n (rst_n & pll_locked), 32 | .in_rgb (pix_data), 33 | .pix_x (pix_x), 34 | .pix_y (pix_y), 35 | .hsync (hsync), 36 | .vsync (vsync), 37 | .out_rgb (rgb) 38 | ); 39 | endmodule 40 | -------------------------------------------------------------------------------- /vga_ctrl/vga_ctrl.csv: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Intel Corporation. All rights reserved. 2 | # Your use of Intel Corporation's design tools, logic functions 3 | # and other software and tools, and any partner logic 4 | # functions, and any output files from any of the foregoing 5 | # (including device programming or simulation files), and any 6 | # associated documentation or information are expressly subject 7 | # to the terms and conditions of the Intel Program License 8 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 9 | # the Intel FPGA IP License Agreement, or other applicable license 10 | # agreement, including, without limitation, that your use is for 11 | # the sole purpose of programming logic devices manufactured by 12 | # Intel and sold by Intel or its authorized distributors. Please 13 | # refer to the applicable agreement for further details, at 14 | # https://fpgasoftware.intel.com/eula. 15 | 16 | # Quartus Prime Version 20.1.1 Build 720 11/11/2020 SJ Lite Edition 17 | # File: C:\Users\Michael\Git\GitHub\learn-verilog\vga_ctrl\vga_ctrl.csv 18 | # Generated on: Sat Aug 20 22:28:36 2022 19 | 20 | # Note: The column header names should not be changed if you wish to import this .csv file into the Quartus Prime software. 21 | 22 | To,Direction,Location,I/O Bank,VREF Group,Fitter Location,I/O Standard,Reserved,Current Strength,Slew Rate,Differential Pair,Strict Preservation 23 | clk,Input,PIN_E1,1,B1_N0,PIN_E1,2.5 V,,,,, 24 | hsync,Output,PIN_C2,1,B1_N0,PIN_C2,2.5 V,,,,, 25 | rgb[15],Output,PIN_A5,8,B8_N0,PIN_A5,2.5 V,,,,, 26 | rgb[14],Output,PIN_E6,8,B8_N0,PIN_E6,2.5 V,,,,, 27 | rgb[13],Output,PIN_E7,8,B8_N0,PIN_E7,2.5 V,,,,, 28 | rgb[12],Output,PIN_B8,8,B8_N0,PIN_B8,2.5 V,,,,, 29 | rgb[11],Output,PIN_A8,8,B8_N0,PIN_A8,2.5 V,,,,, 30 | rgb[10],Output,PIN_F8,8,B8_N0,PIN_F8,2.5 V,,,,, 31 | rgb[9],Output,PIN_E8,8,B8_N0,PIN_E8,2.5 V,,,,, 32 | rgb[8],Output,PIN_B7,8,B8_N0,PIN_B7,2.5 V,,,,, 33 | rgb[7],Output,PIN_A7,8,B8_N0,PIN_A7,2.5 V,,,,, 34 | rgb[6],Output,PIN_F7,8,B8_N0,PIN_F7,2.5 V,,,,, 35 | rgb[5],Output,PIN_F6,8,B8_N0,PIN_F6,2.5 V,,,,, 36 | rgb[4],Output,PIN_B6,8,B8_N0,PIN_B6,2.5 V,,,,, 37 | rgb[3],Output,PIN_A6,8,B8_N0,PIN_A6,2.5 V,,,,, 38 | rgb[2],Output,PIN_B5,8,B8_N0,PIN_B5,2.5 V,,,,, 39 | rgb[1],Output,PIN_A2,8,B8_N0,PIN_A2,2.5 V,,,,, 40 | rgb[0],Output,PIN_B4,8,B8_N0,PIN_B4,2.5 V,,,,, 41 | rst_n,Input,PIN_M15,5,B5_N0,PIN_M15,2.5 V,,,,, 42 | vsync,Output,PIN_D1,1,B1_N0,PIN_D1,2.5 V,,,,, 43 | -------------------------------------------------------------------------------- /vga_ctrl/vga_ctrl.v: -------------------------------------------------------------------------------- 1 | /*********************************************************************************************** 2 | 3 | VGA Timings: http://martin.hinner.info/vga/timing.html 4 | 5 | ┌────────────────┬───────────┬────────────────────────────────┬────────────────────────────────┐ 6 | │ │ │ H Sync │ V Sync │ 7 | │ Display Mode │ Clock/MHz ├───────┬───────┬────────┬───────┼───────┬───────┬────────┬───────┤ 8 | │ │ │ Sync │ Back │ Active │ Front │ Sync │ Back │ Active │ Front │ 9 | │ │ │ Pulse │ Porch │ Video │ Porch │ Pulse │ Porch │ Video │ Porch │ 10 | ├────────────────┼───────────┼───────┼───────┼────────┼───────┼───────┼───────┼────────┼───────┤ 11 | │ 640 x 480 @ 60 │ 25.175 │ 96 │ 48 │ 640 │ 16 │ 2 │ 33 │ 480 │ 10 │ 12 | └────────────────┴───────────┴───────┴───────┴────────┴───────┴───────┴───────┴────────┴───────┘ 13 | 14 | ***********************************************************************************************/ 15 | 16 | module vga_ctrl #( 17 | parameter PIX_REQ_OFFSET = 1, // default to 1 18 | parameter RGB_WIDTH = 16 // 16 = RGB-565, 24 = RGB-888 19 | ) 20 | ( 21 | input wire clk, 22 | input wire rst_n, 23 | input wire [RGB_WIDTH-1:0] in_rgb, 24 | 25 | output wire hsync, 26 | output wire vsync, 27 | output wire pix_data_req, 28 | output wire [9:0] pix_x, 29 | output wire [9:0] pix_y, 30 | output wire [RGB_WIDTH-1:0] out_rgb 31 | ); 32 | 33 | `define DATA_0 10'd0 34 | 35 | parameter H_SYNC = 10'd96, 36 | H_BACK = 10'd48, 37 | H_SIZE = 10'd640, 38 | H_FRONT = 10'd16, 39 | H_TOTAL = H_SYNC + H_BACK + H_SIZE + H_FRONT, // 800 40 | V_SYNC = 10'd2, 41 | V_BACK = 10'd33, 42 | V_SIZE = 10'd480, 43 | V_FRONT = 10'd10, 44 | V_TOTAL = V_SYNC + V_BACK + V_SIZE + V_FRONT; // 525 45 | 46 | // 0 ~ 799 47 | reg [9:0] cnt_h; 48 | 49 | // 0 ~ 524 50 | reg [9:0] cnt_v; 51 | 52 | wire pix_valid; 53 | 54 | always @ (posedge clk or negedge rst_n) begin 55 | if (! rst_n) 56 | cnt_h <= `DATA_0; 57 | else if (cnt_h == H_TOTAL - 1) 58 | cnt_h <= `DATA_0; 59 | else 60 | cnt_h <= cnt_h + 1; 61 | end 62 | 63 | always @ (posedge clk or negedge rst_n) begin 64 | if (! rst_n) 65 | cnt_v <= `DATA_0; 66 | else begin 67 | if (cnt_h == H_TOTAL - 1) begin 68 | if (cnt_v == V_TOTAL - 1) 69 | cnt_v <= `DATA_0; 70 | else 71 | cnt_v <= cnt_v + 1; 72 | end else begin 73 | cnt_v <= cnt_v; 74 | end 75 | end 76 | end 77 | 78 | assign pix_valid = rst_n 79 | && (cnt_h >= (H_SYNC + H_BACK)) 80 | && (cnt_h < (H_SYNC + H_BACK + H_SIZE)) 81 | && (cnt_v >= (V_SYNC + V_BACK)) 82 | && (cnt_v < (V_SYNC + V_BACK + V_SIZE)) 83 | ? 1'b1 : 1'b0; 84 | 85 | assign pix_data_req = rst_n 86 | && (cnt_h >= (H_SYNC + H_BACK - PIX_REQ_OFFSET)) 87 | && (cnt_h < (H_SYNC + H_BACK + H_SIZE - PIX_REQ_OFFSET)) 88 | && (cnt_v >= (V_SYNC + V_BACK)) 89 | && (cnt_v < (V_SYNC + V_BACK + V_SIZE)) 90 | ? 1'b1 : 1'b0; 91 | 92 | assign pix_x = pix_data_req == 1'b1 ? (cnt_h - (H_SYNC + H_BACK - PIX_REQ_OFFSET)) : `DATA_0; 93 | assign pix_y = pix_data_req == 1'b1 ? (cnt_v - (V_SYNC + V_BACK)) : `DATA_0; 94 | 95 | assign hsync = cnt_h < H_SYNC ? 1'b1 : 1'b0; 96 | 97 | assign vsync = cnt_v < V_SYNC ? 1'b1 : 1'b0; 98 | 99 | assign out_rgb = pix_valid == 1'b1 ? in_rgb : {RGB_WIDTH{1'b0}}; 100 | 101 | endmodule 102 | -------------------------------------------------------------------------------- /vga_ctrl/vga_data.v: -------------------------------------------------------------------------------- 1 | module vga_data ( 2 | input wire clk, 3 | input wire rst_n, 4 | input wire [9:0] pix_x, 5 | input wire [9:0] pix_y, 6 | 7 | output reg [15:0] pix_rgb 8 | ); 9 | 10 | `define BLACK 16'h0000 11 | `define RED 16'hf800 12 | `define GREEN 16'h07e0 13 | `define BLUE 16'h001f 14 | `define ORANGE 16'hfc00 15 | `define CYAN 16'h07ff 16 | `define GRAY 16'hd69a 17 | `define WHITE 16'hffff 18 | 19 | always @ (posedge clk or negedge rst_n) begin 20 | if (rst_n == 1'b0) 21 | pix_rgb <= `BLACK; 22 | // border: 23 | else if (pix_x < 1 || pix_y < 1 || pix_x >= 639 || pix_y >= 479) 24 | pix_rgb <= `RED; 25 | // (120, 100) - (220, 180) 26 | else if (pix_x >= 120 && pix_x < 220 && pix_y >= 100 && pix_y < 180) 27 | pix_rgb <= `RED; 28 | // (420, 100) - (520, 180) 29 | else if (pix_x >= 420 && pix_x < 520 && pix_y >= 100 && pix_y < 180) 30 | pix_rgb <= `RED; 31 | // (220, 300) - (420, 380) 32 | else if (pix_x >= 220 && pix_x < 420 && pix_y >= 300 && pix_y < 380) 33 | pix_rgb <= `BLUE; 34 | else 35 | pix_rgb <= `GRAY; 36 | end 37 | 38 | endmodule 39 | -------------------------------------------------------------------------------- /vga_display/README.md: -------------------------------------------------------------------------------- 1 | # VGA Display 2 | 3 | Display 80x25 text mode as VGA output. 4 | 5 | # Generate Font for ROM 6 | 7 | The ROM file `font.mif` is generated by script: 8 | 9 | ``` 10 | $ ../resources/script/gen_font.py \ 11 | --input ../resources/font/ascii-font.png \ 12 | --output ./font.mif 13 | ``` 14 | 15 | # Generate Buffer for RAM 16 | 17 | The RAM file `char-buffer.mif` is generated by script: 18 | 19 | ``` 20 | $ ../resources/script/gen_char_buffer.py \ 21 | --input ../resources/font/init-screen.txt \ 22 | --output ./char-buffer.mif 23 | ``` 24 | 25 | # Generate Index Color to RGB 26 | 27 | The source file `index_color_to_rgb.v` is generated by script: 28 | 29 | ``` 30 | $ ../resources/script/gen_index_color_to_rgb.py \ 31 | --width 16 \ 32 | --output ./index_color_to_rgb.v 33 | ``` 34 | -------------------------------------------------------------------------------- /vga_display/clk_delay.v: -------------------------------------------------------------------------------- 1 | 2 | module clk_delay #( 3 | parameter WIDTH = 8 4 | ) 5 | ( 6 | input wire clk, 7 | input wire [WIDTH-1:0] in_data, 8 | output reg [WIDTH-1:0] out_data 9 | ); 10 | always @ (posedge clk) begin 11 | out_data <= in_data; 12 | end 13 | endmodule 14 | -------------------------------------------------------------------------------- /vga_display/index_color_to_rgb.v: -------------------------------------------------------------------------------- 1 | // VGA 16 Color Palette: 2 | // https://en.wikipedia.org/wiki/Color_Graphics_Adapter 3 | 4 | module index_color_to_rgb ( 5 | input wire [3:0] color_index, 6 | output reg [15:0] color_rgb 7 | ); 8 | always @ (*) begin 9 | case (color_index) 10 | 4'd0: color_rgb = 16'b00000_000000_00000; // #000000 = black 11 | 4'd1: color_rgb = 16'b00000_000000_10101; // #0000aa = blue 12 | 4'd2: color_rgb = 16'b00000_101010_00000; // #00aa00 = green 13 | 4'd3: color_rgb = 16'b00000_101010_10101; // #00aaaa = cyan 14 | 4'd4: color_rgb = 16'b10101_000000_00000; // #aa0000 = red 15 | 4'd5: color_rgb = 16'b10101_000000_10101; // #aa00aa = magenta 16 | 4'd6: color_rgb = 16'b10101_010101_00000; // #aa5500 = brown 17 | 4'd7: color_rgb = 16'b10101_101010_10101; // #aaaaaa = light gray 18 | 4'd8: color_rgb = 16'b01010_010101_01010; // #555555 = dark gray 19 | 4'd9: color_rgb = 16'b01010_010101_11111; // #5555ff = light blue 20 | 4'd10: color_rgb = 16'b01010_111111_01010; // #55ff55 = light green 21 | 4'd11: color_rgb = 16'b01010_111111_11111; // #55ffff = light cyan 22 | 4'd12: color_rgb = 16'b11111_010101_01010; // #ff5555 = light red 23 | 4'd13: color_rgb = 16'b11111_010101_11111; // #ff55ff = light magenta 24 | 4'd14: color_rgb = 16'b11111_111111_01010; // #ffff55 = yellow 25 | 4'd15: color_rgb = 16'b11111_111111_11111; // #ffffff = white 26 | endcase 27 | end 28 | endmodule 29 | -------------------------------------------------------------------------------- /vga_display/pixel_index_color.v: -------------------------------------------------------------------------------- 1 | 2 | module pixel_index_color ( 3 | input valid, 4 | input [7:0] font_line_data, 5 | input [2:0] char_pix_x, 6 | input [7:0] bg_fg_index, 7 | output [3:0] color_index 8 | ); 9 | reg pix; 10 | 11 | always @ (*) begin 12 | case (char_pix_x) 13 | 3'd0: pix = font_line_data[7]; 14 | 3'd1: pix = font_line_data[6]; 15 | 3'd2: pix = font_line_data[5]; 16 | 3'd3: pix = font_line_data[4]; 17 | 3'd4: pix = font_line_data[3]; 18 | 3'd5: pix = font_line_data[2]; 19 | 3'd6: pix = font_line_data[1]; 20 | 3'd7: pix = font_line_data[0]; 21 | endcase 22 | end 23 | 24 | // if pix is 1, return fg color index, otherwise bg color: 25 | assign color_index = valid ? (pix == 1'b1 ? bg_fg_index[3:0] : bg_fg_index[7:4]) : 4'd0; 26 | 27 | endmodule 28 | -------------------------------------------------------------------------------- /vga_display/pixel_to_char.v: -------------------------------------------------------------------------------- 1 | module pixel_to_char ( 2 | input pix_req, 3 | // pixel x of screen: 0 ~ 639: 4 | input [9:0] pix_x, 5 | // pixel y of screen: 0 ~ 479: 6 | input [9:0] pix_y, 7 | 8 | // is char valid: 9 | output reg char_valid, 10 | // char index: 0 ~ 1999: 11 | output wire [10:0] char_index, 12 | // pixel x of char: 0 ~ 7: 13 | output reg [2:0] char_pixel_x, 14 | // pixel y of char: 0 ~ 15: 15 | output reg [3:0] char_pixel_y 16 | ); 17 | 18 | parameter PIX_Y_START = 10'd32, 19 | PIX_Y_END = PIX_Y_START + 25 * 16; 20 | 21 | reg [10:0] row; 22 | reg [10:0] col; 23 | 24 | always @ (*) begin 25 | if (pix_req && pix_y >= PIX_Y_START && pix_y < PIX_Y_END) begin 26 | char_valid = 1'b1; 27 | row = (pix_y - PIX_Y_START) >> 4; 28 | col = pix_x >> 3; 29 | char_pixel_x = pix_x[2:0] & 3'b111; 30 | char_pixel_y = pix_y[3:0] & 4'b1111; 31 | end 32 | else begin 33 | char_valid = 1'b0; 34 | row = 11'b0; 35 | col = 11'b0; 36 | char_pixel_x = 3'b0; 37 | char_pixel_y = 4'b0; 38 | end 39 | end 40 | 41 | assign char_index = row * 11'd80 + col; 42 | endmodule 43 | -------------------------------------------------------------------------------- /vga_display/pll_vga.ppf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /vga_display/pll_vga.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "ALTPLL" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "pll_vga.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll_vga_inst.v"] 6 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll_vga.ppf"] 7 | -------------------------------------------------------------------------------- /vga_display/pll_vga_inst.v: -------------------------------------------------------------------------------- 1 | pll_vga pll_vga_inst ( 2 | .areset ( areset_sig ), 3 | .inclk0 ( inclk0_sig ), 4 | .c0 ( c0_sig ), 5 | .locked ( locked_sig ) 6 | ); 7 | -------------------------------------------------------------------------------- /vga_display/ram_buffer.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "RAM: 2-PORT" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "ram_buffer.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "ram_buffer_inst.v"] 6 | -------------------------------------------------------------------------------- /vga_display/ram_buffer_inst.v: -------------------------------------------------------------------------------- 1 | ram_buffer ram_buffer_inst ( 2 | .data ( data_sig ), 3 | .rdaddress ( rdaddress_sig ), 4 | .rdclock ( rdclock_sig ), 5 | .wraddress ( wraddress_sig ), 6 | .wrclock ( wrclock_sig ), 7 | .wren ( wren_sig ), 8 | .q ( q_sig ) 9 | ); 10 | -------------------------------------------------------------------------------- /vga_display/rom_font.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "ROM: 1-PORT" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "rom_font.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "rom_font_inst.v"] 6 | -------------------------------------------------------------------------------- /vga_display/rom_font_inst.v: -------------------------------------------------------------------------------- 1 | rom_font rom_font_inst ( 2 | .address ( address_sig ), 3 | .clock ( clock_sig ), 4 | .q ( q_sig ) 5 | ); 6 | -------------------------------------------------------------------------------- /vga_display/tb_pixel_to_char.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module tb_pixel_to_char (); 4 | reg pix_req; 5 | reg [9:0] pix_x; 6 | reg [9:0] pix_y; 7 | reg [31:0] cnt; 8 | 9 | pixel_to_char component( 10 | .pix_x(pix_x), 11 | .pix_y(pix_y) 12 | ); 13 | 14 | initial begin 15 | pix_req = 1'b1; 16 | pix_x = 10'b0; 17 | pix_y = 10'b0; 18 | cnt = 32'b0; 19 | #10 20 | while (cnt < 640 * 480 + 100) begin 21 | cnt = cnt + 1'b1; 22 | #2 23 | if (pix_x == 639) begin 24 | pix_x = 10'b0; 25 | if (pix_y == 479) 26 | pix_y = 10'b0; 27 | else 28 | pix_y = pix_y + 1'b1; 29 | end 30 | else begin 31 | pix_x = pix_x + 1'b1; 32 | pix_y = pix_y; 33 | end 34 | end 35 | $finish; 36 | end 37 | 38 | initial begin 39 | $dumpfile("tb_pixel_to_char.vcd"); 40 | $dumpvars(0, component); 41 | end 42 | endmodule 43 | -------------------------------------------------------------------------------- /vga_display/tb_top.v: -------------------------------------------------------------------------------- 1 | `timescale 1ps/1ps 2 | 3 | module tb_top ( 4 | output wire hsync, 5 | output wire vsync, 6 | output wire [15:0] rgb, 7 | 8 | // char index: 0 ~ 1999: 9 | output wire [10:0] char_index, 10 | // char data: 2 bytes: BG/FG color, ASCII code: 11 | output wire [15:0] char_data, 12 | output wire [7:0] color_index_delay, 13 | // char pixel x, y: 14 | output wire [2:0] char_pixel_x, 15 | output wire [3:0] char_pixel_y, 16 | output wire [2:0] char_pixel_x_delay_1, 17 | output wire [2:0] char_pixel_x_delay_2, 18 | output wire [3:0] char_pixel_y_delay, 19 | 20 | // a single byte represent a line of char font: 21 | output wire [7:0] font_line_data, 22 | // pixel color index: 23 | output wire [3:0] pixel_color_index, 24 | // pixel rgb color: 25 | output wire [15:0] pix_rgb, 26 | 27 | // pixel x, y: 28 | output wire [9:0] pix_x, 29 | output wire [9:0] pix_y 30 | ); 31 | 32 | reg vga_clk; 33 | reg vga_rst_n; 34 | 35 | clk_delay #(3) clk_delay_for_char_pixel_x_1 ( 36 | .clk (vga_clk), 37 | .in_data (char_pixel_x), 38 | .out_data (char_pixel_x_delay_1) 39 | ); 40 | 41 | clk_delay #(3) clk_delay_for_char_pixel_x_2 ( 42 | .clk (vga_clk), 43 | .in_data (char_pixel_x_delay_1), 44 | .out_data (char_pixel_x_delay_2) 45 | ); 46 | 47 | clk_delay #(4) clk_delay_for_char_pixel_y ( 48 | .clk (vga_clk), 49 | .in_data (char_pixel_y), 50 | .out_data (char_pixel_y_delay) 51 | ); 52 | 53 | rom_font rom_font_inst ( 54 | .clock (vga_clk), 55 | .address ({ char_data[7:0], char_pixel_y_delay}), 56 | .q (font_line_data) 57 | ); 58 | 59 | clk_delay #(8) clk_delay_for_color_index ( 60 | .clk (vga_clk), 61 | .in_data (char_data[15:8]), 62 | .out_data (color_index_delay) 63 | ); 64 | 65 | pixel_index_color pixel_index_color_inst ( 66 | .font_line_data (font_line_data), 67 | .char_pix_x (char_pixel_x_delay_2), 68 | .bg_fg_index (color_index_delay), 69 | .color_index (pixel_color_index) 70 | ); 71 | 72 | index_color_to_rgb index_color_to_rgb_inst ( 73 | .color_index (pixel_color_index), 74 | .color_rgb (pix_rgb) 75 | ); 76 | 77 | ram_buffer ram_buffer_inst ( 78 | .rdclock (vga_clk), 79 | .wrclock (vga_clk), 80 | .data (16'd0), 81 | .rdaddress (char_index), 82 | .wraddress (11'd0), 83 | .wren (1'b0), 84 | .q (char_data) 85 | ); 86 | 87 | vga_ctrl vga_ctrl_inst ( 88 | .clk (vga_clk), 89 | .rst_n (vga_rst_n), 90 | .in_rgb (pix_rgb), 91 | .pix_x (pix_x), 92 | .pix_y (pix_y), 93 | .hsync (hsync), 94 | .vsync (vsync), 95 | .out_rgb (rgb) 96 | ); 97 | 98 | pixel_to_char pixel_to_char_inst ( 99 | .pix_x (pix_x), 100 | .pix_y (pix_y), 101 | .char_index (char_index), 102 | .char_pixel_x (char_pixel_x), 103 | .char_pixel_y (char_pixel_y) 104 | ); 105 | 106 | initial begin 107 | vga_clk = 1'b1; 108 | vga_rst_n = 1'b0; 109 | #10 110 | vga_rst_n = 1'b1; 111 | #5000000 112 | $finish; 113 | end 114 | 115 | always #1 vga_clk = ~vga_clk; 116 | 117 | endmodule 118 | -------------------------------------------------------------------------------- /vga_display/tb_vga_ctrl.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module tb_vga_ctrl (); 4 | 5 | reg clk; 6 | reg rst_n; 7 | reg [15:0] in_rgb; 8 | 9 | vga_ctrl component( 10 | .clk(clk), 11 | .rst_n(rst_n), 12 | .in_rgb(in_rgb) 13 | ); 14 | 15 | initial begin 16 | clk = 1'b1; 17 | rst_n = 1'b0; 18 | in_rgb = 15'b0; 19 | #10 20 | rst_n = 1'b1; 21 | #5000000 22 | $finish; 23 | end 24 | 25 | always #1 clk = ~clk; 26 | 27 | always #16 in_rgb = in_rgb + 1'b1; 28 | 29 | initial begin 30 | $dumpfile("tb_vga_ctrl.vcd"); 31 | $dumpvars(0, component); 32 | end 33 | endmodule 34 | -------------------------------------------------------------------------------- /vga_display/top.v: -------------------------------------------------------------------------------- 1 | module top( 2 | input wire sys_clk, 3 | input wire sys_rst_n, 4 | // input wire wr_en, 5 | // input wire [9:0] wr_address, 6 | // input wire [15:0] wr_data, 7 | output wire hsync, 8 | output wire vsync, 9 | output wire [15:0] rgb 10 | ); 11 | wire vga_clk; 12 | wire vga_rst_n; 13 | wire pll_locked; 14 | 15 | wire char_valid; 16 | wire char_valid_delay_1; 17 | wire char_valid_delay_2; 18 | // char index: 0 ~ 1999: 19 | wire [10:0] char_index; 20 | // char data: 2 bytes: BG/FG color, ASCII code: 21 | wire [15:0] char_data; 22 | wire [7:0] color_index_delay; 23 | // char pixel x, y: 24 | wire [2:0] char_pixel_x; 25 | wire [3:0] char_pixel_y; 26 | wire [2:0] char_pixel_x_delay_1; 27 | wire [2:0] char_pixel_x_delay_2; 28 | wire [3:0] char_pixel_y_delay; 29 | 30 | // a single byte represent a line of char font: 31 | wire [7:0] font_line_data; 32 | // pixel color index: 33 | wire [3:0] pixel_color_index; 34 | // pixel rgb color: 35 | wire [15:0] pix_rgb; 36 | 37 | wire pix_data_req; 38 | // pixel x, y: 39 | wire [9:0] pix_x; 40 | wire [9:0] pix_y; 41 | 42 | pll_vga pll_vga_inst ( 43 | .areset (~sys_rst_n), 44 | .inclk0 (sys_clk), 45 | .c0 (vga_clk), 46 | .locked(pll_locked) 47 | ); 48 | 49 | assign vga_rst_n = sys_rst_n & pll_locked; 50 | 51 | clk_delay #(1) clk_delay_for_char_valid_1 ( 52 | .clk (vga_clk), 53 | .in_data (char_valid), 54 | .out_data (char_valid_delay_1) 55 | ); 56 | 57 | clk_delay #(1) clk_delay_for_char_valid_2 ( 58 | .clk (vga_clk), 59 | .in_data (char_valid_delay_1), 60 | .out_data (char_valid_delay_2) 61 | ); 62 | 63 | clk_delay #(3) clk_delay_for_char_pixel_x_1 ( 64 | .clk (vga_clk), 65 | .in_data (char_pixel_x), 66 | .out_data (char_pixel_x_delay_1) 67 | ); 68 | 69 | clk_delay #(3) clk_delay_for_char_pixel_x_2 ( 70 | .clk (vga_clk), 71 | .in_data (char_pixel_x_delay_1), 72 | .out_data (char_pixel_x_delay_2) 73 | ); 74 | 75 | clk_delay #(4) clk_delay_for_char_pixel_y ( 76 | .clk (vga_clk), 77 | .in_data (char_pixel_y), 78 | .out_data (char_pixel_y_delay) 79 | ); 80 | 81 | rom_font rom_font_inst ( 82 | .clock (vga_clk), 83 | .address ({ char_data[7:0], char_pixel_y_delay}), 84 | .q (font_line_data) 85 | ); 86 | 87 | clk_delay #(8) clk_delay_for_color_index ( 88 | .clk (vga_clk), 89 | .in_data (char_data[15:8]), 90 | .out_data (color_index_delay) 91 | ); 92 | 93 | pixel_index_color pixel_index_color_inst ( 94 | .valid (char_valid_delay_2), 95 | .font_line_data (font_line_data), 96 | .char_pix_x (char_pixel_x_delay_2), 97 | .bg_fg_index (color_index_delay), 98 | .color_index (pixel_color_index) 99 | ); 100 | 101 | index_color_to_rgb index_color_to_rgb_inst ( 102 | .color_index (pixel_color_index), 103 | .color_rgb (pix_rgb) 104 | ); 105 | 106 | ram_buffer ram_buffer_inst ( 107 | .rdclock (vga_clk), 108 | .wrclock (sys_clk), 109 | .data (16'd0), 110 | .rdaddress (char_index), 111 | .wraddress (11'd0), 112 | .wren (1'b0), 113 | .q (char_data) 114 | ); 115 | 116 | vga_ctrl #(2) vga_ctrl_inst ( 117 | .clk (vga_clk), 118 | .rst_n (vga_rst_n), 119 | .in_rgb (pix_rgb), 120 | .pix_data_req (pix_data_req), 121 | .pix_x (pix_x), 122 | .pix_y (pix_y), 123 | .hsync (hsync), 124 | .vsync (vsync), 125 | .out_rgb (rgb) 126 | ); 127 | 128 | pixel_to_char pixel_to_char_inst ( 129 | .pix_req (pix_data_req), 130 | .pix_x (pix_x), 131 | .pix_y (pix_y), 132 | .char_valid (char_valid), 133 | .char_index (char_index), 134 | .char_pixel_x (char_pixel_x), 135 | .char_pixel_y (char_pixel_y) 136 | ); 137 | endmodule 138 | -------------------------------------------------------------------------------- /vga_display/vga_ctrl.v: -------------------------------------------------------------------------------- 1 | /*********************************************************************************************** 2 | 3 | VGA Timings: http://martin.hinner.info/vga/timing.html 4 | 5 | ┌────────────────┬───────────┬────────────────────────────────┬────────────────────────────────┐ 6 | │ │ │ H Sync │ V Sync │ 7 | │ Display Mode │ Clock/MHz ├───────┬───────┬────────┬───────┼───────┬───────┬────────┬───────┤ 8 | │ │ │ Sync │ Back │ Active │ Front │ Sync │ Back │ Active │ Front │ 9 | │ │ │ Pulse │ Porch │ Video │ Porch │ Pulse │ Porch │ Video │ Porch │ 10 | ├────────────────┼───────────┼───────┼───────┼────────┼───────┼───────┼───────┼────────┼───────┤ 11 | │ 640 x 480 @ 60 │ 25.175 │ 96 │ 48 │ 640 │ 16 │ 2 │ 33 │ 480 │ 10 │ 12 | └────────────────┴───────────┴───────┴───────┴────────┴───────┴───────┴───────┴────────┴───────┘ 13 | 14 | ***********************************************************************************************/ 15 | 16 | module vga_ctrl #( 17 | parameter PIX_REQ_OFFSET = 1, // default to 1 18 | parameter RGB_WIDTH = 16 // 16 = RGB-565, 24 = RGB-888 19 | ) 20 | ( 21 | input clk, 22 | input rst_n, 23 | input [RGB_WIDTH-1:0] in_rgb, 24 | 25 | output hsync, 26 | output vsync, 27 | output pix_data_req, 28 | output [9:0] pix_x, 29 | output [9:0] pix_y, 30 | output pix_valid, 31 | output [RGB_WIDTH-1:0] out_rgb 32 | ); 33 | 34 | localparam DATA_0 = 10'd0; 35 | 36 | localparam H_SYNC = 10'd96, 37 | H_BACK = 10'd48, 38 | H_SIZE = 10'd640, 39 | H_FRONT = 10'd16, 40 | H_TOTAL = H_SYNC + H_BACK + H_SIZE + H_FRONT, // 800 41 | V_SYNC = 10'd2, 42 | V_BACK = 10'd33, 43 | V_SIZE = 10'd480, 44 | V_FRONT = 10'd10, 45 | V_TOTAL = V_SYNC + V_BACK + V_SIZE + V_FRONT; // 525 46 | 47 | // 0 ~ 799 48 | reg [9:0] cnt_h; 49 | 50 | // 0 ~ 524 51 | reg [9:0] cnt_v; 52 | 53 | always @ (posedge clk or negedge rst_n) begin 54 | if (! rst_n) 55 | cnt_h <= DATA_0; 56 | else if (cnt_h == H_TOTAL - 1) 57 | cnt_h <= DATA_0; 58 | else 59 | cnt_h <= cnt_h + 1; 60 | end 61 | 62 | always @ (posedge clk or negedge rst_n) begin 63 | if (! rst_n) 64 | cnt_v <= DATA_0; 65 | else begin 66 | if (cnt_h == H_TOTAL - 1) begin 67 | if (cnt_v == V_TOTAL - 1) 68 | cnt_v <= DATA_0; 69 | else 70 | cnt_v <= cnt_v + 1; 71 | end else begin 72 | cnt_v <= cnt_v; 73 | end 74 | end 75 | end 76 | 77 | wire pix_v_sync_valid; 78 | 79 | assign pix_v_sync_valid = (cnt_v >= (V_SYNC + V_BACK)) 80 | && (cnt_v < (V_SYNC + V_BACK + V_SIZE)) ? 1'b1 : 1'b0; 81 | 82 | assign pix_valid = rst_n 83 | && (cnt_h >= (H_SYNC + H_BACK)) 84 | && (cnt_h < (H_SYNC + H_BACK + H_SIZE)) 85 | && pix_v_sync_valid 86 | ? 1'b1 : 1'b0; 87 | 88 | assign pix_data_req = rst_n 89 | && (cnt_h >= (H_SYNC + H_BACK - PIX_REQ_OFFSET)) 90 | && (cnt_h < (H_SYNC + H_BACK + H_SIZE - PIX_REQ_OFFSET)) 91 | && pix_v_sync_valid 92 | ? 1'b1 : 1'b0; 93 | 94 | assign pix_x = pix_data_req == 1'b1 ? (cnt_h - (H_SYNC + H_BACK - PIX_REQ_OFFSET)) : DATA_0; 95 | assign pix_y = pix_data_req == 1'b1 ? (cnt_v - (V_SYNC + V_BACK)) : DATA_0; 96 | 97 | assign hsync = cnt_h < H_SYNC ? 1'b1 : 1'b0; 98 | 99 | assign vsync = cnt_v < V_SYNC ? 1'b1 : 1'b0; 100 | 101 | assign out_rgb = pix_valid == 1'b1 ? in_rgb : {RGB_WIDTH{1'b0}}; 102 | 103 | endmodule 104 | -------------------------------------------------------------------------------- /vga_display/vga_display.csv: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 Intel Corporation. All rights reserved. 2 | # Your use of Intel Corporation's design tools, logic functions 3 | # and other software and tools, and any partner logic 4 | # functions, and any output files from any of the foregoing 5 | # (including device programming or simulation files), and any 6 | # associated documentation or information are expressly subject 7 | # to the terms and conditions of the Intel Program License 8 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 9 | # the Intel FPGA IP License Agreement, or other applicable license 10 | # agreement, including, without limitation, that your use is for 11 | # the sole purpose of programming logic devices manufactured by 12 | # Intel and sold by Intel or its authorized distributors. Please 13 | # refer to the applicable agreement for further details, at 14 | # https://fpgasoftware.intel.com/eula. 15 | 16 | # Quartus Prime Version 20.1.1 Build 720 11/11/2020 SJ Lite Edition 17 | # File: C:\Users\Michael\Git\GitHub\learn-verilog\vga_display\vga_display.csv 18 | # Generated on: Tue Aug 30 14:58:54 2022 19 | 20 | # Note: The column header names should not be changed if you wish to import this .csv file into the Quartus Prime software. 21 | 22 | To,Direction,Location,I/O Bank,VREF Group,Fitter Location,I/O Standard,Reserved,Current Strength,Slew Rate,Differential Pair,Strict Preservation 23 | hsync,Output,PIN_C2,1,B1_N0,PIN_C2,2.5 V,,,,, 24 | rgb[0],Output,PIN_B4,8,B8_N0,PIN_B4,2.5 V,,,,, 25 | rgb[1],Output,PIN_A2,8,B8_N0,PIN_A2,2.5 V,,,,, 26 | rgb[2],Output,PIN_B5,8,B8_N0,PIN_B5,2.5 V,,,,, 27 | rgb[3],Output,PIN_A6,8,B8_N0,PIN_A6,2.5 V,,,,, 28 | rgb[4],Output,PIN_B6,8,B8_N0,PIN_B6,2.5 V,,,,, 29 | rgb[5],Output,PIN_F6,8,B8_N0,PIN_F6,2.5 V,,,,, 30 | rgb[6],Output,PIN_F7,8,B8_N0,PIN_F7,2.5 V,,,,, 31 | rgb[7],Output,PIN_A7,8,B8_N0,PIN_A7,2.5 V,,,,, 32 | rgb[8],Output,PIN_B7,8,B8_N0,PIN_B7,2.5 V,,,,, 33 | rgb[9],Output,PIN_E8,8,B8_N0,PIN_E8,2.5 V,,,,, 34 | rgb[10],Output,PIN_F8,8,B8_N0,PIN_F8,2.5 V,,,,, 35 | rgb[11],Output,PIN_A8,8,B8_N0,PIN_A8,2.5 V,,,,, 36 | rgb[12],Output,PIN_B8,8,B8_N0,PIN_B8,2.5 V,,,,, 37 | rgb[13],Output,PIN_E7,8,B8_N0,PIN_E7,2.5 V,,,,, 38 | rgb[14],Output,PIN_E6,8,B8_N0,PIN_E6,2.5 V,,,,, 39 | rgb[15],Output,PIN_A5,8,B8_N0,PIN_A5,2.5 V,,,,, 40 | sys_clk,Input,PIN_E1,1,B1_N0,PIN_E1,,,,,, 41 | sys_rst_n,Input,PIN_M15,5,B5_N0,PIN_M2,,,,,, 42 | vsync,Output,PIN_D1,1,B1_N0,PIN_D1,2.5 V,,,,, 43 | -------------------------------------------------------------------------------- /water_led/water_led.v: -------------------------------------------------------------------------------- 1 | // system clock: 50 MHz = 20 ns 2 | 3 | // 0.5 s = 500 ms = 500_000 us = 500_000_000 ns 4 | 5 | // counter = [0 ~ 25_000_000) 6 | 7 | module water_led 8 | #( 9 | parameter CNT_0 = 25'd0, 10 | parameter CNT_MAX = 25'd25_000_000 - 1 11 | ) 12 | ( 13 | input clk, 14 | input rst, 15 | output [3:0] out 16 | ); 17 | reg [24:0] cnt; 18 | reg move_flag; 19 | reg [3:0] out_reg; 20 | 21 | always @ (posedge clk or negedge rst) begin 22 | if (rst == 1'b0) 23 | cnt <= CNT_0; 24 | else 25 | if (cnt == CNT_MAX) 26 | cnt <= CNT_0; 27 | else 28 | cnt <= cnt + 1; 29 | end 30 | 31 | always @ (posedge clk or negedge rst) begin 32 | if (rst == 1'b0) 33 | out_reg <= 4'b1000; 34 | else 35 | if (move_flag == 1'b1) 36 | if (out_reg == 4'b0001) 37 | out_reg <= 4'b1000; 38 | else 39 | out_reg <= out_reg >> 1; 40 | end 41 | 42 | assign out = ~out_reg; 43 | 44 | endmodule 45 | --------------------------------------------------------------------------------