├── .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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------