├── .DS_Store ├── .gitignore ├── Makefrag ├── README.md ├── lab1 ├── .DS_Store ├── Makefile ├── sim │ └── dummy_sim.v ├── spec │ ├── figs │ │ ├── vivado_options.png │ │ ├── x2go_setup.png │ │ ├── z1_bottom_annotated.png │ │ └── z1_top_annotated.png │ └── spec.md └── src │ ├── z1top.v │ └── z1top.xdc ├── lab2 ├── Makefile ├── sim │ ├── adder_testbench.v │ └── counter_testbench.v ├── spec │ ├── figs │ │ ├── dve.png │ │ └── dve_wave.png │ └── spec.md └── src │ ├── adder_tester.v │ ├── behavioral_adder.v │ ├── counter.v │ ├── full_adder.v │ ├── structural_adder.v │ ├── z1top.v │ └── z1top.xdc ├── lab3 ├── Makefile ├── sim │ ├── dac_tb.v │ ├── debouncer_tb.v │ ├── edge_detector_tb.v │ ├── sq_wave_gen_tb.v │ └── sync_tb.v ├── spec │ ├── figs │ │ ├── audio_out.png │ │ ├── bouncing.png │ │ ├── debouncer.png │ │ ├── metastability.png │ │ ├── pwm.pdf │ │ ├── pwm.png │ │ └── synchronizer.png │ └── spec.md └── src │ ├── button_parser.v │ ├── counter.v │ ├── dac.v │ ├── debouncer.v │ ├── edge_detector.v │ ├── sq_wave_gen.v │ ├── synchronizer.v │ ├── z1top.v │ └── z1top.xdc ├── lab4 ├── Makefile ├── scripts │ └── nco.py ├── sim │ ├── dac_tb.v │ ├── fsm_tb.v │ ├── nco_tb.v │ ├── sine.bin │ └── sq_wave_gen_tb.v ├── spec │ ├── figs │ │ ├── fsm.png │ │ ├── lab4figs.pptx │ │ └── top.png │ └── spec.md └── src │ ├── button_parser.v │ ├── dac.v │ ├── debouncer.v │ ├── edge_detector.v │ ├── fcw_ram.v │ ├── fsm.v │ ├── nco.v │ ├── sine.bin │ ├── sq_wave_gen.v │ ├── synchronizer.v │ ├── z1top.v │ └── z1top.xdc ├── lab5 ├── Makefile ├── sim │ ├── echo_tb.v │ ├── echo_tb.vcd │ ├── simple_echo_tb.v │ ├── uart2uart_tb.v │ └── uart_transmitter_tb.v ├── spec │ ├── figs │ │ ├── 2_rv_beats.pdf │ │ ├── 2_rv_beats.png │ │ ├── 2_rv_beats.svg │ │ ├── backpressure.pdf │ │ ├── backpressure.png │ │ ├── backpressure.svg │ │ ├── high_level_diagram.png │ │ ├── pmod_a.jpg │ │ ├── sink_source.png │ │ ├── uart_frame.png │ │ ├── uart_rx.png │ │ └── uart_tx.png │ └── spec.md └── src │ ├── button_parser.v │ ├── debouncer.v │ ├── edge_detector.v │ ├── synchronizer.v │ ├── uart.v │ ├── uart_receiver.v │ ├── uart_transmitter.v │ ├── z1top.v │ └── z1top.xdc ├── lab6 ├── Makefile ├── sim │ ├── fifo_tb.v │ ├── sine.bin │ └── system_tb.v ├── spec │ ├── figs │ │ ├── Lab6_Block_Diagram.pdf │ │ ├── Lab6_Block_Diagram.png │ │ ├── Lab6_Block_Diagram.xml │ │ ├── fifo_timing.svg │ │ ├── sync_fifo_diagram.png │ │ ├── sync_fifo_read_operation.png │ │ └── sync_fifo_write_operation.png │ └── spec.md └── src │ ├── button_parser.v │ ├── dac.v │ ├── debouncer.v │ ├── edge_detector.v │ ├── fifo.v │ ├── fixed_length_piano.v │ ├── nco.v │ ├── piano_scale_rom.v │ ├── sine.bin │ ├── synchronizer.v │ ├── uart.v │ ├── uart_receiver.v │ ├── uart_transmitter.v │ ├── variable_length_piano.v │ ├── z1top.v │ └── z1top.xdc └── scripts ├── audio_from_sim ├── elaborate.tcl ├── impl.tcl ├── musicxml_parser.py ├── piano ├── piano_scale_generator ├── program.tcl ├── program_2021.tcl ├── rom_generator └── synth.tcl /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.fst 3 | *.tbi 4 | csrc 5 | ucli.key 6 | *.vpd 7 | *.tb 8 | *.tb.daidir 9 | *.wav 10 | *.txt -------------------------------------------------------------------------------- /Makefrag: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) -o pipefail 2 | ABS_TOP := $(subst /cygdrive/c/,C:/, $(shell pwd)) 3 | SCRIPTS := $(ABS_TOP)/../scripts 4 | VIVADO ?= vivado 5 | VIVADO_OPTS ?= -nolog -nojournal -mode batch 6 | FPGA_PART ?= xc7z020clg400-1 7 | RTL += $(subst /cygdrive/c/,C:/, $(shell find $(ABS_TOP)/src -type f -name "*.v")) 8 | CONSTRAINTS += $(subst /cygdrive/c/,C:/, $(shell find $(ABS_TOP)/src -type f -name "*.xdc")) 9 | TOP ?= z1top 10 | VCS := vcs -full64 11 | VCS_OPTS := -notice -line +lint=all,noVCDE,noNS,noSVA-UA -sverilog -timescale=1ns/10ps -debug 12 | SIM_RTL := $(subst /cygdrive/c/,C:/, $(shell find $(ABS_TOP)/sim -type f -name "*.v")) 13 | IVERILOG := iverilog 14 | IVERILOG_OPTS := -D IVERILOG=1 -g2012 -gassertions -Wall -Wno-timescale 15 | VVP := vvp 16 | 17 | sim/%.tb: sim/%.v $(RTL) 18 | cd sim && $(VCS) $(VCS_OPTS) -o $*.tb $(RTL) $*.v -top $* 19 | 20 | sim/%.vpd: sim/%.tb 21 | cd sim && ./$*.tb +verbose=1 +vpdfile+$*.vpd 22 | 23 | sim/%.tbi: sim/%.v $(RTL) 24 | cd sim && $(IVERILOG) $(IVERILOG_OPTS) -o $*.tbi $*.v $(RTL) 25 | 26 | sim/%.fst: sim/%.tbi 27 | cd sim && $(VVP) $*.tbi -fst 28 | 29 | build/target.tcl: $(RTL) $(CONSTRAINTS) 30 | mkdir -p build 31 | truncate -s 0 $@ 32 | echo "set ABS_TOP $(ABS_TOP)" >> $@ 33 | echo "set TOP $(TOP)" >> $@ 34 | echo "set FPGA_PART $(FPGA_PART)" >> $@ 35 | echo "set_param general.maxThreads 4" >> $@ 36 | echo "set_param general.maxBackupLogs 0" >> $@ 37 | echo -n "set RTL { " >> $@ 38 | FLIST="$(RTL)"; for f in $$FLIST; do echo -n "$$f " ; done >> $@ 39 | echo "}" >> $@ 40 | echo -n "set CONSTRAINTS { " >> $@ 41 | FLIST="$(CONSTRAINTS)"; for f in $$FLIST; do echo -n "$$f " ; done >> $@ 42 | echo "}" >> $@ 43 | 44 | setup: build/target.tcl 45 | 46 | elaborate: build/target.tcl $(SCRIPTS)/elaborate.tcl 47 | mkdir -p ./build 48 | cd ./build && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/elaborate.tcl |& tee elaborate.log 49 | 50 | build/synth/$(TOP).dcp: build/target.tcl $(SCRIPTS)/synth.tcl 51 | mkdir -p ./build/synth/ 52 | cd ./build/synth/ && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/synth.tcl |& tee synth.log 53 | 54 | synth: build/synth/$(TOP).dcp 55 | 56 | build/impl/$(TOP).bit: build/synth/$(TOP).dcp $(SCRIPTS)/impl.tcl 57 | mkdir -p ./build/impl/ 58 | cd ./build/impl && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/impl.tcl |& tee impl.log 59 | 60 | impl: build/impl/$(TOP).bit 61 | all: build/impl/$(TOP).bit 62 | 63 | program: build/impl/$(TOP).bit $(SCRIPTS)/program.tcl 64 | cd build/impl && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/program.tcl 65 | 66 | program-force: 67 | cd build/impl && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/program.tcl 68 | 69 | vivado: build 70 | cd build && nohup $(VIVADO) /dev/null 2>&1 & 71 | 72 | lint: 73 | verilator --lint-only --top-module $(TOP) $(RTL) 74 | 75 | sim_build/compile_simlib/synopsys_sim.setup: 76 | mkdir -p sim_build/compile_simlib 77 | cd build/sim_build/compile_simlib && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/compile_simlib.tcl 78 | 79 | compile_simlib: sim_build/compile_simlib/synopsys_sim.setup 80 | 81 | clean: 82 | rm -rf ./build $(junk) *.daidir sim/output.txt \ 83 | sim/*.tb sim/*.daidir sim/csrc \ 84 | sim/ucli.key sim/*.vpd sim/*.vcd \ 85 | sim/*.tbi sim/*.fst sim/*.jou sim/*.log sim/*.out 86 | 87 | .PHONY: setup synth impl program program-force vivado all clean %.tb 88 | .PRECIOUS: sim/%.tb sim/%.tbi sim/%.fst sim/%.vpd 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EECS151/251A FPGA Labs SP22 2 | 3 | For each lab, please find the instructions at **/lab#/spec/spec.md** 4 | 5 | Lab 1: Due next lab (1/26, 1/27) 6 | 7 | Lab 2: Due next lab (2/2, 2/3) 8 | 9 | Lab 3: Due next lab (2/9,2/10) -- checkoff deadline for Lab 1,2 and 3 all on 2/16, 2/17 and 2/23 (Monday 2/21 is an administrative holiday), since we're back on campus 10 | 11 | Lab 4: Due next lab (2/23, 2/24 and 2/28) 12 | 13 | Lab 5: Due next lab (3/9, 3/10, 3/14) 14 | 15 | Lab 6: Due after spring break 16 | 17 | # Link to the Final Project for FPGA 18 | 19 | https://github.com/EECS150/project_skeleton_sp22/ 20 | 21 | # Course Website 22 | 23 | https://inst.eecs.berkeley.edu/~eecs151/sp22/ 24 | 25 | # Resources 26 | 27 | PYNQ-Z1 Reference Manual: https://reference.digilentinc.com/reference/programmable-logic/pynq-z1/reference-manual 28 | 29 | Sample XDC file: https://reference.digilentinc.com/_media/reference/programmable-logic/pynq-z1/pynq-z1_c.zip 30 | 31 | Xilinx 7-series CLB architecture: https://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf 32 | 33 | Xilinx 7-series Memory Resources: https://www.xilinx.com/support/documentation/user_guides/ug473_7Series_Memory_Resources.pdf 34 | 35 | Xilinx 7-series DSP Slice: https://www.xilinx.com/support/documentation/user_guides/ug479_7Series_DSP48E1.pdf 36 | 37 | Vivado 2019.1:https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vivado-design-tools/archive.html 38 | 39 | Vivado Synthesis User Guide 2019.1: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_1/ug901-vivado-synthesis.pdf 40 | 41 | Vivado Implementation User Guide 2019.1: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_1/ug904-vivado-implementation.pdf 42 | 43 | Vivado IDE User Guide 2019.1: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_1/ug893-vivado-ide.pdf 44 | 45 | Vivado Simulation (Tutorial) 2019.1: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_1/ug937-vivado-design-suite-simulation-tutorial.pdf 46 | 47 | -------------------------------------------------------------------------------- /lab1/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab1/.DS_Store -------------------------------------------------------------------------------- /lab1/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefrag 2 | -------------------------------------------------------------------------------- /lab1/sim/dummy_sim.v: -------------------------------------------------------------------------------- 1 | //dummy 2 | -------------------------------------------------------------------------------- /lab1/spec/figs/vivado_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab1/spec/figs/vivado_options.png -------------------------------------------------------------------------------- /lab1/spec/figs/x2go_setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab1/spec/figs/x2go_setup.png -------------------------------------------------------------------------------- /lab1/spec/figs/z1_bottom_annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab1/spec/figs/z1_bottom_annotated.png -------------------------------------------------------------------------------- /lab1/spec/figs/z1_top_annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab1/spec/figs/z1_top_annotated.png -------------------------------------------------------------------------------- /lab1/src/z1top.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module z1top( 4 | input CLK_125MHZ_FPGA, 5 | input [3:0] BUTTONS, 6 | input [1:0] SWITCHES, 7 | output [5:0] LEDS 8 | ); 9 | and(LEDS[0], BUTTONS[0], SWITCHES[0]); 10 | assign LEDS[5:1] = 0; 11 | endmodule 12 | -------------------------------------------------------------------------------- /lab1/src/z1top.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a general .xdc for the PYNQ-Z1 board Rev. C 2 | ## To use it in a project: 3 | ## - uncomment the lines corresponding to used pins 4 | ## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project 5 | 6 | ## Clock signal 125 MHz 7 | 8 | set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { CLK_125MHZ_FPGA }]; #IO_L13P_T2_MRCC_35 Sch=sysclk 9 | #create_clock -add -name sys_clk_pin -period 8.00 -waveform {0 4} [get_ports { sysclk }]; 10 | 11 | ## RGB LEDs 12 | 13 | set_property -dict { PACKAGE_PIN L15 IOSTANDARD LVCMOS33 } [get_ports { LEDS[4] }]; #IO_L22N_T3_AD7N_35 Sch=led4_b 14 | #set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { led4_g }]; #IO_L16P_T2_35 Sch=led4_g 15 | #set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led4_r }]; #IO_L21P_T3_DQS_AD14P_35 Sch=led4_r 16 | #set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led5_b }]; #IO_0_35 Sch=led5_b 17 | #set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { led5_g }]; #IO_L22P_T3_AD7P_35 Sch=led5_g 18 | set_property -dict { PACKAGE_PIN M15 IOSTANDARD LVCMOS33 } [get_ports { LEDS[5] }]; #IO_L23N_T3_35 Sch=led5_r 19 | 20 | ## LEDs 21 | 22 | set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { LEDS[0] }]; #IO_L6N_T0_VREF_34 Sch=led[0] 23 | set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { LEDS[1] }]; #IO_L6P_T0_34 Sch=led[1] 24 | set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { LEDS[2] }]; #IO_L21N_T3_DQS_AD14N_35 Sch=led[2] 25 | set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { LEDS[3] }]; #IO_L23P_T3_35 Sch=led[3] 26 | 27 | ## Buttons 28 | 29 | set_property -dict { PACKAGE_PIN D19 IOSTANDARD LVCMOS33 } [get_ports { BUTTONS[0] }]; #IO_L4P_T0_35 Sch=btn[0] 30 | set_property -dict { PACKAGE_PIN D20 IOSTANDARD LVCMOS33 } [get_ports { BUTTONS[1] }]; #IO_L4N_T0_35 Sch=btn[1] 31 | set_property -dict { PACKAGE_PIN L20 IOSTANDARD LVCMOS33 } [get_ports { BUTTONS[2] }]; #IO_L9N_T1_DQS_AD3N_35 Sch=btn[2] 32 | set_property -dict { PACKAGE_PIN L19 IOSTANDARD LVCMOS33 } [get_ports { BUTTONS[3] }]; #IO_L9P_T1_DQS_AD3P_35 Sch=btn[3] 33 | 34 | ## Switches 35 | 36 | set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { SWITCHES[0] }]; #IO_L7N_T1_AD2N_35 Sch=sw[0] 37 | set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { SWITCHES[1] }]; #IO_L7P_T1_AD2P_35 Sch=sw[1] 38 | -------------------------------------------------------------------------------- /lab2/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefrag 2 | -------------------------------------------------------------------------------- /lab2/sim/adder_testbench.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | `define SECOND 1000000000 4 | `define MS 1000000 5 | 6 | module adder_testbench(); 7 | reg [13:0] a; 8 | reg [13:0] b; 9 | wire [14:0] sum; 10 | 11 | structural_adder sa ( 12 | .a(a), 13 | .b(b), 14 | .sum(sum) 15 | ); 16 | 17 | initial begin 18 | `ifdef IVERILOG 19 | $dumpfile("adder_testbench.fst"); 20 | $dumpvars(0, adder_testbench); 21 | `endif 22 | `ifndef IVERILOG 23 | $vcdpluson; 24 | `endif 25 | 26 | a = 14'd1; 27 | b = 14'd1; 28 | #(2); 29 | assert(sum == 15'd2); 30 | 31 | a = 14'd0; 32 | b = 14'd1; 33 | #(2); 34 | assert(sum == 15'd1) else $display("ERROR: Expected sum to be 1, actual value: %d", sum); 35 | 36 | a = 14'd10; 37 | b = 14'd10; 38 | #(2); 39 | if (sum != 15'd20) begin 40 | $error("Expected sum to be 20, a: %d, b: %d, actual value: %d", a, b, sum); 41 | $fatal(1); 42 | end 43 | 44 | `ifndef IVERILOG 45 | $vcdplusoff; 46 | `endif 47 | $finish(); 48 | end 49 | endmodule 50 | -------------------------------------------------------------------------------- /lab2/sim/counter_testbench.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | `define SECOND 1000000000 4 | `define MS 1000000 5 | 6 | module counter_testbench(); 7 | reg clock = 0; 8 | reg ce; 9 | wire [3:0] LEDS; 10 | 11 | counter ctr ( 12 | .clk(clock), 13 | .ce(ce), 14 | .LEDS(LEDS) 15 | ); 16 | 17 | // Notice that this code causes the `clock` signal to constantly 18 | // switch up and down every 4 time steps. 19 | always #(4) clock <= ~clock; 20 | 21 | initial begin 22 | `ifdef IVERILOG 23 | $dumpfile("counter_testbench.fst"); 24 | $dumpvars(0, counter_testbench); 25 | `endif 26 | `ifndef IVERILOG 27 | $vcdpluson; 28 | `endif 29 | 30 | // TODO: Change input values and step forward in time to test 31 | // your counter and its clock enable/disable functionality. 32 | 33 | 34 | `ifndef IVERILOG 35 | $vcdplusoff; 36 | `endif 37 | $finish(); 38 | end 39 | endmodule 40 | 41 | -------------------------------------------------------------------------------- /lab2/spec/figs/dve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab2/spec/figs/dve.png -------------------------------------------------------------------------------- /lab2/spec/figs/dve_wave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab2/spec/figs/dve_wave.png -------------------------------------------------------------------------------- /lab2/src/adder_tester.v: -------------------------------------------------------------------------------- 1 | module adder_tester ( 2 | output [13:0] adder_operand1, 3 | output [13:0] adder_operand2, 4 | input [14:0] structural_sum, 5 | input [14:0] behavioral_sum, 6 | input clk, 7 | output test_fail 8 | ); 9 | reg error = 0; 10 | assign test_fail = error; 11 | 12 | reg [27:0] operands = 0; 13 | assign adder_operand1 = operands[13:0]; 14 | assign adder_operand2 = operands[27:14]; 15 | 16 | // Iterate the operands continuously until all combinations are tried 17 | always @ (posedge clk) begin 18 | operands <= operands + 1'd1; 19 | end 20 | 21 | // If we encounter a case where the adders don't match, or we have already 22 | // encountered one such case, flip the error register high and hold it there. 23 | always @ (posedge clk) begin 24 | if (structural_sum != behavioral_sum) begin 25 | error <= 1'b1; 26 | end 27 | else begin 28 | error <= error; 29 | end 30 | end 31 | endmodule 32 | -------------------------------------------------------------------------------- /lab2/src/behavioral_adder.v: -------------------------------------------------------------------------------- 1 | module behavioral_adder ( 2 | input [13:0] a, 3 | input [13:0] b, 4 | output [14:0] sum 5 | ); 6 | assign sum = a + b; 7 | endmodule 8 | -------------------------------------------------------------------------------- /lab2/src/counter.v: -------------------------------------------------------------------------------- 1 | module counter ( 2 | input clk, 3 | input ce, 4 | output [3:0] LEDS 5 | ); 6 | // Some initial code has been provided for you 7 | // You can change this code if needed 8 | reg [3:0] led_cnt_value; 9 | assign LEDS = led_cnt_value; 10 | 11 | // TODO: Instantiate a reg net to count the number of cycles 12 | // required to reach one second. Note that our clock period is 8ns. 13 | // Think about how many bits are needed for your reg. 14 | 15 | always @(posedge clk) begin 16 | // TODO: update the reg if clock is enabled (ce is 1). 17 | // Once the requisite number of cycles is reached, increment the count. 18 | 19 | end 20 | endmodule 21 | 22 | -------------------------------------------------------------------------------- /lab2/src/full_adder.v: -------------------------------------------------------------------------------- 1 | module full_adder ( 2 | input a, 3 | input b, 4 | input carry_in, 5 | output sum, 6 | output carry_out 7 | ); 8 | // Insert your RTL here to calculate the sum and carry out bits 9 | // Remove these assign statements once you write your own RTL 10 | 11 | assign sum = 1'b0; 12 | assign carry_out = 1'b0; 13 | endmodule 14 | -------------------------------------------------------------------------------- /lab2/src/structural_adder.v: -------------------------------------------------------------------------------- 1 | module structural_adder ( 2 | input [13:0] a, 3 | input [13:0] b, 4 | output [14:0] sum 5 | ); 6 | assign sum = 15'd0; 7 | endmodule 8 | -------------------------------------------------------------------------------- /lab2/src/z1top.v: -------------------------------------------------------------------------------- 1 | // Comment out this line when you want to instantiate your counter 2 | `define ADDER_CIRCUIT 3 | 4 | module z1top ( 5 | input CLK_125MHZ_FPGA, 6 | input [3:0] BUTTONS, 7 | input [1:0] SWITCHES, 8 | output [5:0] LEDS 9 | ); 10 | 11 | `ifdef ADDER_CIRCUIT 12 | wire [14:0] adder_out; 13 | structural_adder user_adder ( 14 | .a({11'b0,SWITCHES[0],BUTTONS[1:0]}), 15 | .b({11'b0,SWITCHES[1],BUTTONS[3:2]}), 16 | .sum(adder_out) 17 | ); 18 | assign LEDS[3:0] = adder_out[3:0]; // truncate upper bits 19 | 20 | // Self test of the structural adder 21 | wire [13:0] adder_operand1, adder_operand2; 22 | wire [14:0] structural_out, behavioral_out; 23 | wire test_fail; 24 | assign LEDS[4] = ~test_fail; 25 | assign LEDS[5] = ~test_fail; 26 | 27 | structural_adder structural_test_adder ( 28 | .a(adder_operand1), 29 | .b(adder_operand2), 30 | .sum(structural_out) 31 | ); 32 | 33 | behavioral_adder behavioral_test_adder ( 34 | .a(adder_operand1), 35 | .b(adder_operand2), 36 | .sum(behavioral_out) 37 | ); 38 | 39 | adder_tester tester ( 40 | .adder_operand1(adder_operand1), 41 | .adder_operand2(adder_operand2), 42 | .structural_sum(structural_out), 43 | .behavioral_sum(behavioral_out), 44 | .clk(CLK_125MHZ_FPGA), 45 | .test_fail(test_fail) 46 | ); 47 | `else 48 | assign LEDS[5:4] = 0; 49 | 50 | counter ctr ( 51 | .clk(CLK_125MHZ_FPGA), 52 | .ce(SWITCHES[0]), 53 | .LEDS(LEDS[3:0]) 54 | ); 55 | `endif 56 | endmodule 57 | -------------------------------------------------------------------------------- /lab2/src/z1top.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a general .xdc for the PYNQ-Z1 board Rev. C 2 | ## To use it in a project: 3 | ## - uncomment the lines corresponding to used pins 4 | ## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project 5 | 6 | ## Clock signal 125 MHz 7 | 8 | set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { CLK_125MHZ_FPGA }]; #IO_L13P_T2_MRCC_35 Sch=sysclk 9 | create_clock -add -name clk_125mhz_fpga -period 8.00 -waveform {0 4} [get_ports { CLK_125MHZ_FPGA }]; 10 | 11 | ##RGB LEDs 12 | 13 | set_property -dict { PACKAGE_PIN L15 IOSTANDARD LVCMOS33 } [get_ports { LEDS[4] }]; #IO_L22N_T3_AD7N_35 Sch=led4_b 14 | #set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { led4_g }]; #IO_L16P_T2_35 Sch=led4_g 15 | #set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led4_r }]; #IO_L21P_T3_DQS_AD14P_35 Sch=led4_r 16 | #set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led5_b }]; #IO_0_35 Sch=led5_b 17 | #set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { led5_g }]; #IO_L22P_T3_AD7P_35 Sch=led5_g 18 | set_property -dict { PACKAGE_PIN M15 IOSTANDARD LVCMOS33 } [get_ports { LEDS[5] }]; #IO_L23N_T3_35 Sch=led5_r 19 | 20 | ##LEDs 21 | 22 | set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { LEDS[0] }]; #IO_L6N_T0_VREF_34 Sch=led[0] 23 | set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { LEDS[1] }]; #IO_L6P_T0_34 Sch=led[1] 24 | set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { LEDS[2] }]; #IO_L21N_T3_DQS_AD14N_35 Sch=led[2] 25 | set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { LEDS[3] }]; #IO_L23P_T3_35 Sch=led[3] 26 | 27 | ##Buttons 28 | 29 | set_property -dict { PACKAGE_PIN D19 IOSTANDARD LVCMOS33 } [get_ports { BUTTONS[0] }]; #IO_L4P_T0_35 Sch=btn[0] 30 | set_property -dict { PACKAGE_PIN D20 IOSTANDARD LVCMOS33 } [get_ports { BUTTONS[1] }]; #IO_L4N_T0_35 Sch=btn[1] 31 | set_property -dict { PACKAGE_PIN L20 IOSTANDARD LVCMOS33 } [get_ports { BUTTONS[2] }]; #IO_L9N_T1_DQS_AD3N_35 Sch=btn[2] 32 | set_property -dict { PACKAGE_PIN L19 IOSTANDARD LVCMOS33 } [get_ports { BUTTONS[3] }]; #IO_L9P_T1_DQS_AD3P_35 Sch=btn[3] 33 | 34 | ##Switches 35 | 36 | set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { SWITCHES[0] }]; #IO_L7N_T1_AD2N_35 Sch=sw[0] 37 | set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { SWITCHES[1] }]; #IO_L7P_T1_AD2P_35 Sch=sw[1] 38 | 39 | 40 | ## A neat way to assign both the pin signal name and the I/O standard at the same time: 41 | # set_property -dict { PACKAGE_PIN L19 IOSTANDARD LVCMOS33 } [get_ports { BUTTONS[3] }]; 42 | -------------------------------------------------------------------------------- /lab3/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefrag 2 | -------------------------------------------------------------------------------- /lab3/sim/dac_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `define CLK_PERIOD 8 3 | 4 | module dac_tb(); 5 | // Generate 125 Mhz clock 6 | reg clk = 0; 7 | always #(`CLK_PERIOD/2) clk = ~clk; 8 | 9 | // I/O 10 | reg [2:0] code; 11 | wire pwm, next_sample; 12 | 13 | dac #(.CYCLES_PER_WINDOW(8)) DUT ( 14 | .clk(clk), 15 | .code(code), 16 | .pwm(pwm), 17 | .next_sample(next_sample) 18 | ); 19 | 20 | initial begin 21 | `ifdef IVERILOG 22 | $dumpfile("dac_tb.fst"); 23 | $dumpvars(0, dac_tb); 24 | `endif 25 | `ifndef IVERILOG 26 | $vcdpluson; 27 | `endif 28 | 29 | fork 30 | // Thread to drive code and check output 31 | begin 32 | code = 0; 33 | @(posedge clk); #1; 34 | repeat (7) begin 35 | assert(pwm == 0) else $error("pwm should be 0 when code is 0"); 36 | @(posedge clk); #1; 37 | end 38 | assert(pwm == 0) else $error("pwm should be 0 when code is 0"); 39 | 40 | code = 7; 41 | @(posedge clk); #1; 42 | repeat (7) begin 43 | assert(pwm == 1) else $error("pwm should be 1 when code is 7"); 44 | @(posedge clk); #1; 45 | end 46 | assert(pwm == 1) else $error("pwm should be 1 when code is 7"); 47 | 48 | repeat (2) begin 49 | code = 3; 50 | @(posedge clk); #1; 51 | repeat (3) begin 52 | assert(pwm == 1) else $error("pwm should be 1 on first half of code = 3"); 53 | @(posedge clk); #1; 54 | end 55 | repeat (4) begin 56 | assert(pwm == 0) else $error("pwm should be 0 on second half of code = 3"); 57 | @(posedge clk); #1; 58 | end 59 | end 60 | end 61 | // Thread to check next_sample 62 | begin 63 | repeat (4) begin 64 | assert(next_sample == 0) else $error("next_sample should start at 0"); 65 | repeat (7) @(posedge clk); #1; 66 | assert(next_sample == 1) else $error("next_sample should become 1 after 7 cycles"); 67 | @(posedge clk); #1; 68 | assert(next_sample == 0) else $error("next_sample should go back to 0 on the 8th cycle"); 69 | end 70 | end 71 | join 72 | 73 | $display("Test finished"); 74 | 75 | `ifndef IVERILOG 76 | $vcdplusoff; 77 | `endif 78 | $finish(); 79 | end 80 | endmodule 81 | -------------------------------------------------------------------------------- /lab3/sim/debouncer_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | `define CLK_PERIOD 8 4 | `define DEBOUNCER_WIDTH 2 5 | `define SAMPLE_CNT_MAX 10 6 | `define PULSE_CNT_MAX 4 7 | 8 | // This testbench checks that your debouncer smooths-out the input signals properly. Refer to the spec for details. 9 | 10 | module debouncer_tb(); 11 | // Generate 125 MHz clock 12 | reg clk = 0; 13 | always #(`CLK_PERIOD/2) clk = ~clk; 14 | 15 | // I/O of debouncer 16 | reg [`DEBOUNCER_WIDTH-1:0] glitchy_signal; 17 | wire [`DEBOUNCER_WIDTH-1:0] debounced_signal; 18 | 19 | debouncer #( 20 | .WIDTH(`DEBOUNCER_WIDTH), 21 | .SAMPLE_CNT_MAX(`SAMPLE_CNT_MAX), 22 | .PULSE_CNT_MAX(`PULSE_CNT_MAX) 23 | ) DUT ( 24 | .clk(clk), 25 | .glitchy_signal(glitchy_signal), 26 | .debounced_signal(debounced_signal) 27 | ); 28 | 29 | reg test0_done = 0; 30 | integer z; 31 | initial begin 32 | `ifdef IVERILOG 33 | $dumpfile("debouncer_tb.fst"); 34 | $dumpvars(0, debouncer_tb); 35 | for(z = 0; z < `DEBOUNCER_WIDTH; z = z + 1) begin 36 | $dumpvars(0, DUT.saturating_counter[z]); 37 | end 38 | `endif 39 | `ifndef IVERILOG 40 | $vcdpluson; 41 | $vcdplusmemon; 42 | `endif 43 | 44 | glitchy_signal = 0; 45 | repeat (5) @(posedge clk); 46 | #1; 47 | 48 | // We will use our first glitchy_signal to verify that if a signal bounces around and goes low 49 | // before the saturating counter saturates, that the output never goes high 50 | 51 | // Initially act glitchy 52 | repeat(10) begin 53 | glitchy_signal[0] = ~glitchy_signal[0]; 54 | @(posedge clk); #1; 55 | end 56 | 57 | // Drop signal for a full sample period 58 | glitchy_signal[0] = 0; 59 | repeat(`SAMPLE_CNT_MAX + 1) @(posedge clk); 60 | #1; 61 | 62 | // Bring the signal high and hold until before the saturating counter should saturate, then pull low 63 | glitchy_signal[0] = 1; 64 | repeat (`SAMPLE_CNT_MAX * (`PULSE_CNT_MAX - 1)) @(posedge clk); 65 | #1; 66 | 67 | // Pull the signal low and wait, the debouncer shouldn't set its output high 68 | glitchy_signal[0] = 0; 69 | repeat (`SAMPLE_CNT_MAX * (`PULSE_CNT_MAX + 1)) @(posedge clk); 70 | #1; 71 | assert(debounced_signal[0] == 0) else $display("1st debounced_signal didn't stay low"); 72 | 73 | test0_done = 1; 74 | 75 | // We will use the second glitchy_signal to verify that if a signal bounces around and stays high 76 | // long enough for the counter to saturate, that the output goes high and stays there until the glitchy_signal falls 77 | // Initially act glitchy 78 | repeat (10) begin 79 | glitchy_signal[1] = ~glitchy_signal[1]; 80 | @(posedge clk); #1; 81 | end 82 | 83 | // Bring the glitchy signal high and hold past the point at which the debouncer should saturate 84 | glitchy_signal[1] = 1; 85 | repeat (`SAMPLE_CNT_MAX * (`PULSE_CNT_MAX + 1)) @(posedge clk); 86 | #1; 87 | 88 | if (debounced_signal[1] != 1) 89 | $error("Failure 1: The debounced output[1] should have gone high by now %d", $time); 90 | @(posedge clk); #1; 91 | 92 | // While the glitchy signal is high, the debounced output should remain high 93 | repeat (`SAMPLE_CNT_MAX * 3) begin 94 | if (debounced_signal[1] != 1) 95 | $error("Failure 2: The debounced output[1] should stay high once the counter saturates at %d", $time); 96 | @(posedge clk); #1; 97 | end 98 | 99 | // Pull the glitchy signal low and the output should fall after the next sampling period 100 | // The output is only guaranteed to fall after the next sampling period 101 | // Wait until another sampling period has definetely occured 102 | glitchy_signal[1] = 0; 103 | repeat (`SAMPLE_CNT_MAX + 1) @(posedge clk); #1; 104 | 105 | if (debounced_signal[1] != 0) 106 | $error("Failure 3: The debounced output[1] should have falled by now %d", $time); 107 | @(posedge clk); #1; 108 | 109 | // Wait for some time to ensure the signal stays low 110 | repeat (`SAMPLE_CNT_MAX * (`PULSE_CNT_MAX + 1)) begin 111 | if (debounced_signal[1] != 0) 112 | $error("Failure 4: The debounced output[1] should remain low at %d", $time); 113 | @(posedge clk); #1; 114 | end 115 | 116 | repeat (10) @(posedge clk); 117 | 118 | $display("Done!"); 119 | `ifndef IVERILOG 120 | $vcdplusoff; 121 | `endif 122 | $finish(); 123 | end 124 | 125 | // this checks that the output of the first debouncer never goes high 126 | initial begin 127 | while (test0_done == 0) begin 128 | if (debounced_signal[0] != 0) 129 | $error("Failure 0: The debounced output[0] wasn't 0 for the entire test."); 130 | @(posedge clk); 131 | end 132 | end 133 | 134 | endmodule 135 | -------------------------------------------------------------------------------- /lab3/sim/edge_detector_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | `define CLK_PERIOD 8 4 | `define EDGE_DETECTOR_WIDTH 2 5 | 6 | module edge_detector_tb(); 7 | // Generate 125 MHz clock 8 | reg clk = 0; 9 | always #(`CLK_PERIOD/2) clk = ~clk; 10 | 11 | // I/O of edge detector 12 | reg [`EDGE_DETECTOR_WIDTH-1:0] signal_in; 13 | wire [`EDGE_DETECTOR_WIDTH-1:0] edge_detect_pulse; 14 | 15 | edge_detector #( 16 | .WIDTH(`EDGE_DETECTOR_WIDTH) 17 | ) DUT ( 18 | .clk(clk), 19 | .signal_in(signal_in), 20 | .edge_detect_pulse(edge_detect_pulse) 21 | ); 22 | 23 | reg done = 0; 24 | reg [31:0] tests_failed = 0; 25 | 26 | initial begin 27 | `ifdef IVERILOG 28 | $dumpfile("edge_detector_tb.fst"); 29 | $dumpvars(0, edge_detector_tb); 30 | `endif 31 | `ifndef IVERILOG 32 | $vcdpluson; 33 | `endif 34 | 35 | fork 36 | // Stimulus thread 37 | begin 38 | signal_in = 2'b00; 39 | repeat (2) @(posedge clk); #1; 40 | signal_in = 2'b01; 41 | repeat (5) @(posedge clk); #1; 42 | signal_in = 2'b00; 43 | repeat (5) @(posedge clk); #1; 44 | signal_in = 2'b10; 45 | repeat (3) @(posedge clk); #1; 46 | signal_in = 2'b00; 47 | repeat (10) @(posedge clk); #1; 48 | if (!done) begin 49 | $error("Testbench timeout"); 50 | $fatal(); 51 | end 52 | else begin 53 | $display("Testbench finished, errors: %d", tests_failed); 54 | end 55 | end 56 | // Output checker thread 57 | begin 58 | // Wait for the rising edge of the edge detector output 59 | @(posedge edge_detect_pulse[0]); 60 | 61 | // Let 1 clock cycle elapse 62 | @(posedge clk); #1; 63 | 64 | // Check that the edge detector output is now low 65 | if (edge_detect_pulse[0] !== 1'b0) begin 66 | $error("Failure 1: Your edge detector's output wasn't 1 clock cycle wide"); 67 | tests_failed = tests_failed + 1; 68 | end 69 | 70 | // Wait for the 2nd rising edge, and same logic, but for the second bit 71 | @(posedge edge_detect_pulse[1]); 72 | @(posedge clk); #1; 73 | if (edge_detect_pulse[1] !== 1'b0) begin 74 | $error("Failure 2: Your edge detector's output wasn't 1 clock cycle wide"); 75 | tests_failed = tests_failed + 1; 76 | end 77 | done = 1; 78 | end 79 | join 80 | 81 | `ifndef IVERILOG 82 | $vcdplusoff; 83 | `endif 84 | $finish(); 85 | end 86 | 87 | always @(posedge edge_detect_pulse[0] or posedge edge_detect_pulse[1]) begin 88 | $display("DEBUG: Detected rising edge at time %d", $time); 89 | end 90 | endmodule 91 | -------------------------------------------------------------------------------- /lab3/sim/sq_wave_gen_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `define CLK_PERIOD 8 3 | 4 | module sq_wave_gen_tb(); 5 | // Generate 125 Mhz clock 6 | reg clk = 0; 7 | always #(`CLK_PERIOD/2) clk = ~clk; 8 | 9 | // I/O 10 | wire [9:0] code; 11 | reg next_sample; 12 | 13 | sq_wave_gen DUT ( 14 | .clk(clk), 15 | .code(code), 16 | .next_sample(next_sample) 17 | ); 18 | 19 | integer code_file; 20 | integer next_sample_fetch; 21 | initial begin 22 | `ifdef IVERILOG 23 | $dumpfile("sq_wave_gen_tb.fst"); 24 | $dumpvars(0, sq_wave_gen_tb); 25 | `endif 26 | `ifndef IVERILOG 27 | $vcdpluson; 28 | `endif 29 | 30 | code_file = $fopen("codes.txt", "w"); 31 | 32 | next_sample = 0; 33 | @(posedge clk); #1; 34 | 35 | repeat (122000) begin 36 | // Pull next_sample every X cycles where X is a random number in [2, 9] 37 | next_sample_fetch = ($urandom() % 8) + 2; 38 | repeat (next_sample_fetch) @(posedge clk); 39 | #1; 40 | next_sample = 1; 41 | @(posedge clk); #1; 42 | $fwrite(code_file, "%d\n", code); 43 | next_sample = 0; 44 | @(posedge clk); #1; 45 | end 46 | $fclose(code_file); 47 | 48 | `ifndef IVERILOG 49 | $vcdplusoff; 50 | `endif 51 | $finish(); 52 | end 53 | endmodule 54 | -------------------------------------------------------------------------------- /lab3/sim/sync_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `define CLK_PERIOD 8 3 | 4 | // This testbench checks that your synchronizer is made up of 2 flip-flops serially connected. 5 | // This testbench cannot model metastability. 6 | 7 | module sync_tb(); 8 | // Generate 125 Mhz clock 9 | reg clk = 0; 10 | always #(`CLK_PERIOD/2) clk = ~clk; 11 | 12 | // I/O of synchronizer 13 | reg async_signal; 14 | wire sync_signal; 15 | 16 | synchronizer #(.WIDTH(1)) DUT ( 17 | .clk(clk), 18 | .async_signal(async_signal), 19 | .sync_signal(sync_signal) 20 | ); 21 | 22 | initial begin 23 | `ifdef IVERILOG 24 | $dumpfile("sync_tb.fst"); 25 | $dumpvars(0, sync_tb); 26 | `endif 27 | `ifndef IVERILOG 28 | $vcdpluson; 29 | `endif 30 | 31 | // We use fork-join to create 2 threads that operate in parallel 32 | fork 33 | // This first thread will send a test signal into the DUT's async_signal input 34 | begin 35 | async_signal = 1'b0; 36 | #(`CLK_PERIOD * 2) async_signal = 1'b1; 37 | #(`CLK_PERIOD * 1) async_signal = 1'b0; 38 | #(`CLK_PERIOD * 3) async_signal = 1'b1; 39 | #(`CLK_PERIOD * 2) async_signal = 1'b0; 40 | #(`CLK_PERIOD * 4) async_signal = 1'b1; 41 | end 42 | 43 | // This second thread will monitor the DUT's sync_signal output for the correct response 44 | // The #1 is a Verilog oddity that's needed since the sync_signal changes after the rising edge of the clock, 45 | // not at the same instant as the rising edge. 46 | begin 47 | repeat (4) @(posedge clk); #1 if (sync_signal !== 1'b1) $error("Check 1 failed"); 48 | repeat (1) @(posedge clk); #1 if (sync_signal !== 1'b0) $error("Check 2 failed"); 49 | repeat (3) @(posedge clk); #1 if (sync_signal !== 1'b1) $error("Check 3 failed"); 50 | repeat (2) @(posedge clk); #1 if (sync_signal !== 1'b0) $error("Check 4 failed"); 51 | repeat (4) @(posedge clk); #1 if (sync_signal !== 1'b1) $error("Check 5 failed"); 52 | end 53 | join 54 | 55 | repeat (3) @(posedge clk); // Wait for a little time and perform the final check again 56 | if (sync_signal !== 1'b1) $error("Check 6 failed"); 57 | 58 | $display("Test finished"); 59 | 60 | `ifndef IVERILOG 61 | $vcdplusoff; 62 | `endif 63 | $finish(); 64 | end 65 | endmodule 66 | -------------------------------------------------------------------------------- /lab3/spec/figs/audio_out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab3/spec/figs/audio_out.png -------------------------------------------------------------------------------- /lab3/spec/figs/bouncing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab3/spec/figs/bouncing.png -------------------------------------------------------------------------------- /lab3/spec/figs/debouncer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab3/spec/figs/debouncer.png -------------------------------------------------------------------------------- /lab3/spec/figs/metastability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab3/spec/figs/metastability.png -------------------------------------------------------------------------------- /lab3/spec/figs/pwm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab3/spec/figs/pwm.pdf -------------------------------------------------------------------------------- /lab3/spec/figs/pwm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab3/spec/figs/pwm.png -------------------------------------------------------------------------------- /lab3/spec/figs/synchronizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab3/spec/figs/synchronizer.png -------------------------------------------------------------------------------- /lab3/src/button_parser.v: -------------------------------------------------------------------------------- 1 | // This module instantiates the synchronizer -> debouncer -> edge detector signal chain for button inputs 2 | module button_parser #( 3 | parameter WIDTH = 1, 4 | parameter SAMPLE_CNT_MAX = 62500, 5 | parameter PULSE_CNT_MAX = 200 6 | ) ( 7 | input clk, 8 | input [WIDTH-1:0] in, 9 | output [WIDTH-1:0] out 10 | ); 11 | wire [WIDTH-1:0] synchronized_signals; 12 | wire [WIDTH-1:0] debounced_signals; 13 | 14 | synchronizer # ( 15 | .WIDTH(WIDTH) 16 | ) button_synchronizer ( 17 | .clk(clk), 18 | .async_signal(in), 19 | .sync_signal(synchronized_signals) 20 | ); 21 | 22 | debouncer # ( 23 | .WIDTH(WIDTH), 24 | .SAMPLE_CNT_MAX(SAMPLE_CNT_MAX), 25 | .PULSE_CNT_MAX(PULSE_CNT_MAX) 26 | ) button_debouncer ( 27 | .clk(clk), 28 | .glitchy_signal(synchronized_signals), 29 | .debounced_signal(debounced_signals) 30 | ); 31 | 32 | edge_detector # ( 33 | .WIDTH(WIDTH) 34 | ) button_edge_detector ( 35 | .clk(clk), 36 | .signal_in(debounced_signals), 37 | .edge_detect_pulse(out) 38 | ); 39 | endmodule 40 | -------------------------------------------------------------------------------- /lab3/src/counter.v: -------------------------------------------------------------------------------- 1 | module counter #( 2 | parameter CYCLES_PER_SECOND = 125_000_000 3 | )( 4 | input clk, 5 | input ce, 6 | input [3:0] buttons, 7 | output [3:0] leds 8 | ); 9 | reg [3:0] counter = 0; 10 | assign leds = counter; 11 | 12 | always @(posedge clk) begin 13 | if (buttons[0]) 14 | counter <= counter + 4'd1; 15 | else if (buttons[1]) 16 | counter <= counter - 4'd1; 17 | else if (buttons[3]) 18 | counter <= 4'd0; 19 | else 20 | counter <= counter; 21 | end 22 | endmodule 23 | 24 | -------------------------------------------------------------------------------- /lab3/src/dac.v: -------------------------------------------------------------------------------- 1 | module dac #( 2 | parameter CYCLES_PER_WINDOW = 1024, 3 | parameter CODE_WIDTH = $clog2(CYCLES_PER_WINDOW) 4 | )( 5 | input clk, 6 | input [CODE_WIDTH-1:0] code, 7 | output next_sample, 8 | output pwm 9 | ); 10 | assign pwm = 0; 11 | assign next_sample = 0; 12 | endmodule 13 | -------------------------------------------------------------------------------- /lab3/src/debouncer.v: -------------------------------------------------------------------------------- 1 | module debouncer #( 2 | parameter WIDTH = 1, 3 | parameter SAMPLE_CNT_MAX = 62500, 4 | parameter PULSE_CNT_MAX = 200, 5 | parameter WRAPPING_CNT_WIDTH = $clog2(SAMPLE_CNT_MAX), 6 | parameter SAT_CNT_WIDTH = $clog2(PULSE_CNT_MAX) + 1 7 | ) ( 8 | input clk, 9 | input [WIDTH-1:0] glitchy_signal, 10 | output [WIDTH-1:0] debounced_signal 11 | ); 12 | // TODO: fill in neccesary logic to implement the wrapping counter and the saturating counters 13 | // Some initial code has been provided to you, but feel free to change it however you like 14 | // One wrapping counter is required 15 | // One saturating counter is needed for each bit of glitchy_signal 16 | // You need to think of the conditions for reseting, clock enable, etc. those registers 17 | // Refer to the block diagram in the spec 18 | 19 | // Remove this line once you have created your debouncer 20 | assign debounced_signal = 0; 21 | 22 | reg [SAT_CNT_WIDTH-1:0] saturating_counter [WIDTH-1:0]; 23 | endmodule 24 | -------------------------------------------------------------------------------- /lab3/src/edge_detector.v: -------------------------------------------------------------------------------- 1 | module edge_detector #( 2 | parameter WIDTH = 1 3 | )( 4 | input clk, 5 | input [WIDTH-1:0] signal_in, 6 | output [WIDTH-1:0] edge_detect_pulse 7 | ); 8 | // TODO: implement a multi-bit edge detector that detects a rising edge of 'signal_in[x]' 9 | // and outputs a one-cycle pulse 'edge_detect_pulse[x]' at the next clock edge 10 | // Feel free to use as many number of registers you like 11 | 12 | // Remove this line once you create your edge detector 13 | assign edge_detect_pulse = 0; 14 | endmodule 15 | -------------------------------------------------------------------------------- /lab3/src/sq_wave_gen.v: -------------------------------------------------------------------------------- 1 | module sq_wave_gen ( 2 | input clk, 3 | input next_sample, 4 | output [9:0] code 5 | ); 6 | assign code = 0; 7 | endmodule 8 | -------------------------------------------------------------------------------- /lab3/src/synchronizer.v: -------------------------------------------------------------------------------- 1 | module synchronizer #(parameter WIDTH = 1) ( 2 | input [WIDTH-1:0] async_signal, 3 | input clk, 4 | output [WIDTH-1:0] sync_signal 5 | ); 6 | // TODO: Create your 2 flip-flop synchronizer here 7 | // This module takes in a vector of WIDTH-bit asynchronous 8 | // (from different clock domain or not clocked, such as button press) signals 9 | // and should output a vector of WIDTH-bit synchronous signals 10 | // that are synchronized to the input clk 11 | 12 | // Remove this line once you create your synchronizer 13 | assign sync_signal = 0; 14 | endmodule 15 | -------------------------------------------------------------------------------- /lab3/src/z1top.v: -------------------------------------------------------------------------------- 1 | `define CLOCK_FREQ 125_000_000 2 | 3 | module z1top ( 4 | input CLK_125MHZ_FPGA, 5 | input [3:0] BUTTONS, 6 | input [1:0] SWITCHES, 7 | output [5:0] LEDS, 8 | output AUD_PWM, 9 | output AUD_SD 10 | ); 11 | assign LEDS[5:4] = 2'b11; 12 | 13 | // Button parser test circuit 14 | // Sample the button signal every 500us 15 | localparam integer B_SAMPLE_CNT_MAX = $rtoi(0.0005 * `CLOCK_FREQ); 16 | // The button is considered 'pressed' after 100ms of continuous pressing 17 | localparam integer B_PULSE_CNT_MAX = $rtoi(0.100 / 0.0005); 18 | 19 | wire [3:0] buttons_pressed; 20 | button_parser #( 21 | .WIDTH(4), 22 | .SAMPLE_CNT_MAX(B_SAMPLE_CNT_MAX), 23 | .PULSE_CNT_MAX(B_PULSE_CNT_MAX) 24 | ) bp ( 25 | .clk(CLK_125MHZ_FPGA), 26 | .in(BUTTONS), 27 | .out(buttons_pressed) 28 | ); 29 | 30 | counter count ( 31 | .clk(CLK_125MHZ_FPGA), 32 | .ce(SWITCHES[0]), 33 | .buttons(buttons_pressed), 34 | .leds(LEDS[3:0]) 35 | ); 36 | 37 | assign AUD_SD = SWITCHES[1]; // 1 = audio enabled 38 | wire [9:0] code; 39 | wire next_sample; 40 | dac #( 41 | .CYCLES_PER_WINDOW(1024) 42 | ) dac ( 43 | .clk(CLK_125MHZ_FPGA), 44 | .code(code), 45 | .next_sample(next_sample), 46 | .pwm(AUD_PWM) 47 | ); 48 | 49 | sq_wave_gen gen ( 50 | .clk(CLK_125MHZ_FPGA), 51 | .next_sample(next_sample), 52 | .code(code) 53 | ); 54 | endmodule 55 | -------------------------------------------------------------------------------- /lab3/src/z1top.xdc: -------------------------------------------------------------------------------- 1 | ## Source: https://reference.digilentinc.com/_media/reference/programmable-logic/pynq-z1/pynq-z1_c.zip 2 | ## 3 | 4 | ## Clock signal 125 MHz 5 | 6 | set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { CLK_125MHZ_FPGA }]; 7 | create_clock -add -name clk_125mhz_fpga -period 8.00 -waveform {0 4} [get_ports { CLK_125MHZ_FPGA }]; 8 | 9 | ## RGB LEDs 10 | 11 | set_property -dict { PACKAGE_PIN L15 IOSTANDARD LVCMOS33 } [get_ports { LEDS[4] }]; 12 | set_property -dict { PACKAGE_PIN M15 IOSTANDARD LVCMOS33 } [get_ports { LEDS[5] }]; 13 | 14 | ## LEDs 15 | 16 | set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {LEDS[0]}] 17 | set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports {LEDS[1]}] 18 | set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports {LEDS[2]}] 19 | set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports {LEDS[3]}] 20 | 21 | ## Buttons 22 | 23 | set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports {BUTTONS[0]}] 24 | set_property -dict {PACKAGE_PIN D20 IOSTANDARD LVCMOS33} [get_ports {BUTTONS[1]}] 25 | set_property -dict {PACKAGE_PIN L20 IOSTANDARD LVCMOS33} [get_ports {BUTTONS[2]}] 26 | set_property -dict {PACKAGE_PIN L19 IOSTANDARD LVCMOS33} [get_ports {BUTTONS[3]}] 27 | 28 | ## Switches 29 | 30 | set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports {SWITCHES[0]}] 31 | set_property -dict {PACKAGE_PIN M19 IOSTANDARD LVCMOS33} [get_ports {SWITCHES[1]}] 32 | 33 | ## Audio Out 34 | set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { AUD_PWM }]; 35 | set_property -dict { PACKAGE_PIN T17 IOSTANDARD LVCMOS33 } [get_ports { AUD_SD }]; 36 | -------------------------------------------------------------------------------- /lab4/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefrag 2 | -------------------------------------------------------------------------------- /lab4/scripts/nco.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Requires: pip install spfpm 3 | 4 | from FixedPoint import FXfamily, FXnum 5 | from enum import Enum, auto 6 | import numpy as np 7 | import sys 8 | from typing import Tuple 9 | import argparse 10 | 11 | NCOType = Tuple[FXnum, FXnum, FXnum, FXnum] 12 | output_type = FXfamily(n_bits=16, n_intbits=4) 13 | 14 | class NCO: 15 | def __init__(self, fsamp: float, interpolate: bool) -> None: 16 | self.fsamp = fsamp 17 | self.interpolate = interpolate 18 | self.output_type = output_type 19 | self.phase_acc = 0 # type: int 20 | self.N = 24 21 | self.M = 8 22 | self.lut_entries = 2**self.M 23 | self.DAC = 1024 24 | 25 | self.sine_lut_float = [np.sin(i * 2*np.pi / self.lut_entries) for i in range(self.lut_entries)] 26 | self.sine_lut_fixed = [FXnum(x, family=self.output_type) for x in self.sine_lut_float] 27 | self.sine_lut_int = [int((x + 1) * self.DAC / 2) for x in self.sine_lut_float] 28 | 29 | self.square_lut_fixed = [FXnum(1, family=self.output_type) for x in range(int(self.lut_entries/2))] + \ 30 | [FXnum(-1, family=self.output_type) for x in range(int(self.lut_entries/2))] 31 | 32 | self.triangle_lut_float = [np.max(1 - np.abs(x)) for x in np.linspace(-1, 1, self.lut_entries)] 33 | self.triangle_lut_float = [x*2 - 1 for x in self.triangle_lut_float] # scale to range from -1 to 1 34 | self.triangle_lut_fixed = [FXnum(x, family=self.output_type) for x in self.triangle_lut_float] 35 | 36 | self.sawtooth_lut_float = [x - np.floor(x) for x in np.linspace(0, 1-1e-16, self.lut_entries)] 37 | self.sawtooth_lut_float = [x*2 - 1 for x in self.sawtooth_lut_float] # scaling again 38 | self.sawtooth_lut_fixed = [FXnum(x, family=self.output_type) for x in self.sawtooth_lut_float] 39 | 40 | def next_sample(self, fcw: int) -> NCOType: 41 | lut_index = (self.phase_acc >> (self.N - self.M)) & int('1'*self.M, 2) # take MSB M bits of phase_acc 42 | samples = [] 43 | for lut in [self.sine_lut_fixed, self.square_lut_fixed, self.triangle_lut_fixed, self.sawtooth_lut_fixed]: 44 | if self.interpolate is False: 45 | samples.append(lut[lut_index]) 46 | else: 47 | samp1 = lut[lut_index] 48 | samp2 = lut[(lut_index + 1) % self.lut_entries] 49 | residual = self.phase_acc & int('1'*(self.N - self.M), 2) # take LSB (N-M) bits of phase_acc 50 | residual = FXnum(residual/(2**(self.N - self.M)), family=self.output_type) # Cast residual as fixed point 51 | diff = samp2 - samp1 52 | samples.append(samp1 + residual*diff) 53 | 54 | self.phase_acc = self.phase_acc + fcw 55 | self.phase_acc = self.phase_acc % 2**self.N # overflow on N bits 56 | return samples 57 | 58 | def next_sample_f(self, freq: float) -> Tuple[FXnum, FXnum, FXnum, FXnum]: 59 | return self.next_sample(self.phase_increment(freq)) 60 | 61 | def phase_increment(self, freq: float) -> int: 62 | return int(round((freq / self.fsamp) * 2**self.N)) 63 | 64 | def effective_frequency(self, phase_increment: int) -> float: 65 | return (phase_increment * self.fsamp) / (2**self.N) 66 | 67 | def reset(self) -> None: 68 | self.phase_acc = 0 69 | 70 | if __name__ == "__main__": 71 | parser = argparse.ArgumentParser(description='NCO Model') 72 | parser.add_argument('--analysis', dest='analysis', action='store_true', help='compare ideal sampling with NCO samples') 73 | # parser.add_argument('--golden', dest='golden', action='store_true', help='dump golden NCO samples for comparison with RTL') 74 | parser.add_argument('--sine-lut', dest='sine_lut', action='store_true', help='dump the sine LUT values') 75 | # parser.add_argument('--square-lut', dest='square_lut', action='store_true', help='dump the square LUT values') 76 | # parser.add_argument('--triangle-lut', dest='triangle_lut', action='store_true', help='dump the triangle LUT values') 77 | # parser.add_argument('--sawtooth-lut', dest='sawtooth_lut', action='store_true', help='dump the sawtooth LUT values') 78 | parser.add_argument('--sine-plot', dest='sine_plot', action='store_true', help='plot the sine LUT values') 79 | # parser.add_argument('--square-plot', dest='square_plot', action='store_true', help='plot the square LUT values') 80 | # parser.add_argument('--triangle-plot', dest='triangle_plot', action='store_true', help='plot the triangle LUT values') 81 | # parser.add_argument('--sawtooth-plot', dest='sawtooth_plot', action='store_true', help='plot the sawtooth LUT values') 82 | args = parser.parse_args() 83 | 84 | fsamp = 30e3 85 | nco = NCO(fsamp, interpolate = True) 86 | fsig = 880 87 | num_periods = 5 88 | num_samples = int(np.ceil(fsamp / fsig)) * num_periods 89 | nco_samples = [nco.next_sample_f(fsig) for n in range(num_samples)] # only take the sine sample 90 | 91 | if args.analysis: 92 | nco_sine_samples = [x[0] for x in nco_samples] 93 | nco_samples_float = [float(x) for x in nco_sine_samples] 94 | phase_increment = nco.phase_increment(fsig) 95 | effective_freq = nco.effective_frequency(phase_increment) 96 | ideal_samples = [np.sin(2*np.pi*effective_freq*n/fsamp) for n in range(num_samples)] 97 | 98 | ## Plot NCO vs ideal samples 99 | import matplotlib.pyplot as plt 100 | fig, ax = plt.subplots(2, 1) 101 | ax[0].plot(nco_samples_float, '*') 102 | ax[0].plot(ideal_samples, '*') 103 | ax[0].legend(['NCO Samples', 'Ideal Samples']) 104 | ax[0].set_xlabel('Sample Number (n)') 105 | ax[0].set_ylabel('Amplitude') 106 | ax[1].plot(np.abs(np.array(nco_samples_float) - np.array(ideal_samples))) 107 | ax[1].legend(['NCO Error']) 108 | ax[1].set_xlabel('Sample Number (n)') 109 | ax[1].set_ylabel('Absolute Error') 110 | plt.show() 111 | 112 | # if args.golden: 113 | # for val in nco_samples: 114 | # print('{}'.format(val[0].toBinaryString().replace('.', ''))) # only consider the sine samples 115 | # print(">>>", nco.sine_lut_fixed[1]) 116 | # print(">>>", nco.sine_lut_int[1]) 117 | # print(">>>", '{0:10b}'.format(nco.sine_lut_int[1])) 118 | if args.sine_lut: 119 | # sine_lut = [x.toBinaryString() for x in nco.sine_lut_fixed] 120 | # for val in sine_lut: 121 | # print('{}'.format(val.replace('.', ''))) 122 | for val in nco.sine_lut_int: 123 | if val >= nco.DAC: 124 | val = nco.DAC - 1 125 | print('{0:010b}'.format(val)) 126 | if args.sine_plot: 127 | import matplotlib.pyplot as plt 128 | #sine_lut = [float(x) for x in nco.sine_lut_fixed] 129 | sine_lut = [float(x) for x in nco.sine_lut_int] 130 | plt.plot(sine_lut, '.') 131 | plt.show() 132 | 133 | # if args.square_lut: 134 | # square_lut = [x.toBinaryString() for x in nco.square_lut_fixed] 135 | # for val in square_lut: 136 | # print('{}'.format(val.replace('.', ''))) 137 | # if args.square_plot: 138 | # import matplotlib.pyplot as plt 139 | # square_lut = [float(x) for x in nco.square_lut_fixed] 140 | # plt.plot(square_lut, '.') 141 | # plt.show() 142 | 143 | # if args.triangle_lut: 144 | # triangle_lut = [x.toBinaryString() for x in nco.triangle_lut_fixed] 145 | # for val in triangle_lut: 146 | # print('{}'.format(val.replace('.', ''))) 147 | # if args.triangle_plot: 148 | # import matplotlib.pyplot as plt 149 | # triangle_lut = [float(x) for x in nco.triangle_lut_fixed] 150 | # plt.plot(triangle_lut, '.') 151 | # plt.show() 152 | 153 | # if args.sawtooth_lut: 154 | # saw_lut = [x.toBinaryString() for x in nco.sawtooth_lut_fixed] 155 | # for val in saw_lut: 156 | # print('{}'.format(val.replace('.', ''))) 157 | # if args.sawtooth_plot: 158 | # import matplotlib.pyplot as plt 159 | # sawtooth_lut = [float(x) for x in nco.sawtooth_lut_fixed] 160 | # plt.plot(sawtooth_lut, '.') 161 | # plt.show() 162 | -------------------------------------------------------------------------------- /lab4/sim/dac_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `define CLK_PERIOD 8 3 | 4 | module dac_tb(); 5 | // Generate 125 Mhz clock 6 | reg clk = 0; 7 | always #(`CLK_PERIOD/2) clk = ~clk; 8 | 9 | // I/O 10 | reg [2:0] code; 11 | wire pwm, next_sample; 12 | reg rst; 13 | 14 | dac #(.CYCLES_PER_WINDOW(8)) DUT ( 15 | .clk(clk), 16 | .rst(rst), 17 | .code(code), 18 | .pwm(pwm), 19 | .next_sample(next_sample) 20 | ); 21 | 22 | initial begin 23 | `ifdef IVERILOG 24 | $dumpfile("dac_tb.fst"); 25 | $dumpvars(0, dac_tb); 26 | `endif 27 | `ifndef IVERILOG 28 | $vcdpluson; 29 | `endif 30 | 31 | rst = 1; 32 | @(posedge clk); #1; 33 | rst = 0; 34 | 35 | fork 36 | // Thread to drive code and check output 37 | begin 38 | code = 0; 39 | @(posedge clk); #1; 40 | repeat (7) begin 41 | assert(pwm == 0) else $error("pwm should be 0 when code is 0"); 42 | @(posedge clk); #1; 43 | end 44 | assert(pwm == 0) else $error("pwm should be 0 when code is 0"); 45 | 46 | code = 7; 47 | @(posedge clk); #1; 48 | repeat (7) begin 49 | assert(pwm == 1) else $error("pwm should be 1 when code is 7"); 50 | @(posedge clk); #1; 51 | end 52 | assert(pwm == 1) else $error("pwm should be 1 when code is 7"); 53 | 54 | repeat (2) begin 55 | code = 3; 56 | @(posedge clk); #1; 57 | repeat (3) begin 58 | assert(pwm == 1) else $error("pwm should be 1 on first half of code = 3"); 59 | @(posedge clk); #1; 60 | end 61 | repeat (4) begin 62 | assert(pwm == 0) else $error("pwm should be 0 on second half of code = 3"); 63 | @(posedge clk); #1; 64 | end 65 | end 66 | end 67 | // Thread to check next_sample 68 | begin 69 | repeat (4) begin 70 | assert(next_sample == 0) else $error("next_sample should start at 0"); 71 | repeat (7) @(posedge clk); #1; 72 | assert(next_sample == 1) else $error("next_sample should become 1 after 7 cycles"); 73 | @(posedge clk); #1; 74 | assert(next_sample == 0) else $error("next_sample should go back to 0 on the 8th cycle"); 75 | end 76 | end 77 | join 78 | 79 | $display("Test finished"); 80 | 81 | `ifndef IVERILOG 82 | $vcdplusoff; 83 | `endif 84 | $finish(); 85 | end 86 | endmodule 87 | -------------------------------------------------------------------------------- /lab4/sim/fsm_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `define CLK_PERIOD 8 3 | 4 | module fsm_tb(); 5 | // Generate 125 Mhz clock 6 | reg clk = 0; 7 | always #(`CLK_PERIOD/2) clk = ~clk; 8 | 9 | // I/O 10 | reg rst; 11 | reg [2:0] buttons; 12 | wire [23:0] fcw; 13 | wire [3:0] leds; 14 | wire [1:0] leds_state; 15 | 16 | fsm #(.CYCLES_PER_SECOND(125_000_000)) DUT ( 17 | .clk(clk), 18 | .rst(rst), 19 | .buttons(buttons), 20 | .leds(leds), 21 | .leds_state(leds_state), 22 | .fcw(fcw) 23 | ); 24 | 25 | initial begin 26 | `ifdef IVERILOG 27 | $dumpfile("fsm_tb.fst"); 28 | $dumpvars(0, fsm_tb); 29 | `endif 30 | `ifndef IVERILOG 31 | $vcdpluson; 32 | `endif 33 | 34 | rst = 1; 35 | @(posedge clk); #1; 36 | rst = 0; 37 | 38 | buttons = 0; 39 | 40 | // TODO: toggle the buttons 41 | // verify state transitions with the LEDs 42 | // verify fcw is being set properly by the FSM 43 | 44 | `ifndef IVERILOG 45 | $vcdplusoff; 46 | `endif 47 | $finish(); 48 | end 49 | endmodule 50 | -------------------------------------------------------------------------------- /lab4/sim/nco_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `define CLK_PERIOD 8 3 | 4 | module nco_tb(); 5 | // Generate 125 Mhz clock 6 | reg clk = 0; 7 | always #(`CLK_PERIOD/2) clk = ~clk; 8 | 9 | // I/O 10 | reg [23:0] fcw; 11 | reg rst; 12 | reg next_sample; 13 | wire [9:0] code; 14 | 15 | nco DUT ( 16 | .clk(clk), 17 | .rst(rst), 18 | .fcw(fcw), 19 | .next_sample(next_sample), 20 | .code(code) 21 | ); 22 | 23 | integer code_file; 24 | integer next_sample_fetch; 25 | integer num_samples_fetched = 0; 26 | initial begin 27 | `ifdef IVERILOG 28 | $dumpfile("nco_tb.fst"); 29 | $dumpvars(0, nco_tb); 30 | `endif 31 | `ifndef IVERILOG 32 | $vcdpluson; 33 | `endif 34 | 35 | code_file = $fopen("nco_codes.txt", "w"); 36 | rst = 1; 37 | next_sample = 0; 38 | @(posedge clk); #1; 39 | rst = 0; 40 | 41 | fork 42 | // Thread to pull samples from the NCO 43 | begin 44 | repeat (122000) begin 45 | // Pull next_sample every X cycles where X is a random number in [2, 9] 46 | next_sample_fetch = ($urandom() % 8) + 2; 47 | repeat (next_sample_fetch) @(posedge clk); 48 | #1; 49 | next_sample = 1; 50 | @(posedge clk); #1; 51 | $fwrite(code_file, "%d\n", code); 52 | num_samples_fetched = num_samples_fetched + 1; 53 | next_sample = 0; 54 | @(posedge clk); #1; 55 | end 56 | end 57 | // Thread for you to drive fcw 58 | begin 59 | // the fcw is 24 bits, with the 8 MSB used to index into the sine LUT 60 | // if we set fcw = 2^16, the NCO should index into LUT 61 | // addresses 0, 1, 2, 3, ... for every next_sample 62 | fcw = 'h10000; 63 | @(num_samples_fetched == 20); 64 | 65 | // TODO: play with the fcw to adjust the output frequency 66 | // hint: use the num_samples_fetched integer to wait for 67 | // X samples to be fetched by the sampling thread 68 | fcw = 0; // TODO: change this to play a 440 Hz tone 69 | end 70 | // Thread to check code for fcw = 2^16 71 | begin 72 | // Initially the code comes from address 0 of the LUT 73 | assert(code == 10'b1000000000) else $error("Code on reset should be LUT[0]"); 74 | @(num_samples_fetched == 1); 75 | assert(code == 10'b1000001100) else $error("Code after 1 sample should be LUT[1]"); 76 | @(num_samples_fetched == 2); 77 | assert(code == 10'b1000011001) else $error("Code after 2 samples should be LUT[2]"); 78 | @(num_samples_fetched == 10); 79 | assert(code == 10'b1001111100) else $error("Code after 10 samples should be LUT[10]"); 80 | end 81 | join 82 | 83 | $fclose(code_file); 84 | 85 | `ifndef IVERILOG 86 | $vcdplusoff; 87 | `endif 88 | $finish(); 89 | end 90 | endmodule 91 | -------------------------------------------------------------------------------- /lab4/sim/sine.bin: -------------------------------------------------------------------------------- 1 | 1000000000 2 | 1000001100 3 | 1000011001 4 | 1000100101 5 | 1000110010 6 | 1000111110 7 | 1001001011 8 | 1001010111 9 | 1001100011 10 | 1001110000 11 | 1001111100 12 | 1010001000 13 | 1010010100 14 | 1010100000 15 | 1010101100 16 | 1010111000 17 | 1011000011 18 | 1011001111 19 | 1011011010 20 | 1011100110 21 | 1011110001 22 | 1011111100 23 | 1100000111 24 | 1100010001 25 | 1100011100 26 | 1100100110 27 | 1100110000 28 | 1100111010 29 | 1101000100 30 | 1101001110 31 | 1101010111 32 | 1101100001 33 | 1101101010 34 | 1101110010 35 | 1101111011 36 | 1110000011 37 | 1110001011 38 | 1110010011 39 | 1110011011 40 | 1110100010 41 | 1110101001 42 | 1110110000 43 | 1110110111 44 | 1110111101 45 | 1111000011 46 | 1111001001 47 | 1111001110 48 | 1111010100 49 | 1111011001 50 | 1111011101 51 | 1111100010 52 | 1111100110 53 | 1111101001 54 | 1111101101 55 | 1111110000 56 | 1111110011 57 | 1111110110 58 | 1111111000 59 | 1111111010 60 | 1111111100 61 | 1111111101 62 | 1111111110 63 | 1111111111 64 | 1111111111 65 | 1111111111 66 | 1111111111 67 | 1111111111 68 | 1111111110 69 | 1111111101 70 | 1111111100 71 | 1111111010 72 | 1111111000 73 | 1111110110 74 | 1111110011 75 | 1111110000 76 | 1111101101 77 | 1111101001 78 | 1111100110 79 | 1111100010 80 | 1111011101 81 | 1111011001 82 | 1111010100 83 | 1111001110 84 | 1111001001 85 | 1111000011 86 | 1110111101 87 | 1110110111 88 | 1110110000 89 | 1110101001 90 | 1110100010 91 | 1110011011 92 | 1110010011 93 | 1110001011 94 | 1110000011 95 | 1101111011 96 | 1101110010 97 | 1101101010 98 | 1101100001 99 | 1101010111 100 | 1101001110 101 | 1101000100 102 | 1100111010 103 | 1100110000 104 | 1100100110 105 | 1100011100 106 | 1100010001 107 | 1100000111 108 | 1011111100 109 | 1011110001 110 | 1011100110 111 | 1011011010 112 | 1011001111 113 | 1011000011 114 | 1010111000 115 | 1010101100 116 | 1010100000 117 | 1010010100 118 | 1010001000 119 | 1001111100 120 | 1001110000 121 | 1001100011 122 | 1001010111 123 | 1001001011 124 | 1000111110 125 | 1000110010 126 | 1000100101 127 | 1000011001 128 | 1000001100 129 | 1000000000 130 | 0111110011 131 | 0111100110 132 | 0111011010 133 | 0111001101 134 | 0111000001 135 | 0110110100 136 | 0110101000 137 | 0110011100 138 | 0110001111 139 | 0110000011 140 | 0101110111 141 | 0101101011 142 | 0101011111 143 | 0101010011 144 | 0101000111 145 | 0100111100 146 | 0100110000 147 | 0100100101 148 | 0100011001 149 | 0100001110 150 | 0100000011 151 | 0011111000 152 | 0011101110 153 | 0011100011 154 | 0011011001 155 | 0011001111 156 | 0011000101 157 | 0010111011 158 | 0010110001 159 | 0010101000 160 | 0010011110 161 | 0010010101 162 | 0010001101 163 | 0010000100 164 | 0001111100 165 | 0001110100 166 | 0001101100 167 | 0001100100 168 | 0001011101 169 | 0001010110 170 | 0001001111 171 | 0001001000 172 | 0001000010 173 | 0000111100 174 | 0000110110 175 | 0000110001 176 | 0000101011 177 | 0000100110 178 | 0000100010 179 | 0000011101 180 | 0000011001 181 | 0000010110 182 | 0000010010 183 | 0000001111 184 | 0000001100 185 | 0000001001 186 | 0000000111 187 | 0000000101 188 | 0000000011 189 | 0000000010 190 | 0000000001 191 | 0000000000 192 | 0000000000 193 | 0000000000 194 | 0000000000 195 | 0000000000 196 | 0000000001 197 | 0000000010 198 | 0000000011 199 | 0000000101 200 | 0000000111 201 | 0000001001 202 | 0000001100 203 | 0000001111 204 | 0000010010 205 | 0000010110 206 | 0000011001 207 | 0000011101 208 | 0000100010 209 | 0000100110 210 | 0000101011 211 | 0000110001 212 | 0000110110 213 | 0000111100 214 | 0001000010 215 | 0001001000 216 | 0001001111 217 | 0001010110 218 | 0001011101 219 | 0001100100 220 | 0001101100 221 | 0001110100 222 | 0001111100 223 | 0010000100 224 | 0010001101 225 | 0010010101 226 | 0010011110 227 | 0010101000 228 | 0010110001 229 | 0010111011 230 | 0011000101 231 | 0011001111 232 | 0011011001 233 | 0011100011 234 | 0011101110 235 | 0011111000 236 | 0100000011 237 | 0100001110 238 | 0100011001 239 | 0100100101 240 | 0100110000 241 | 0100111100 242 | 0101000111 243 | 0101010011 244 | 0101011111 245 | 0101101011 246 | 0101110111 247 | 0110000011 248 | 0110001111 249 | 0110011100 250 | 0110101000 251 | 0110110100 252 | 0111000001 253 | 0111001101 254 | 0111011010 255 | 0111100110 256 | 0111110011 257 | -------------------------------------------------------------------------------- /lab4/sim/sq_wave_gen_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `define CLK_PERIOD 8 3 | 4 | module sq_wave_gen_tb(); 5 | // Generate 125 Mhz clock 6 | reg clk = 0; 7 | always #(`CLK_PERIOD/2) clk = ~clk; 8 | 9 | // I/O 10 | wire [9:0] code; 11 | reg [2:0] buttons; 12 | wire [3:0] leds; 13 | reg next_sample; 14 | reg rst; 15 | 16 | sq_wave_gen DUT ( 17 | .clk(clk), 18 | .rst(rst), 19 | .code(code), 20 | .next_sample(next_sample), 21 | .buttons(buttons), 22 | .leds(leds) 23 | ); 24 | 25 | integer code_file; 26 | integer next_sample_fetch; 27 | integer num_samples_fetched = 0; 28 | initial begin 29 | `ifdef IVERILOG 30 | $dumpfile("sq_wave_gen_tb.fst"); 31 | $dumpvars(0, sq_wave_gen_tb); 32 | `endif 33 | `ifndef IVERILOG 34 | $vcdpluson; 35 | `endif 36 | 37 | code_file = $fopen("codes.txt", "w"); 38 | rst = 1; 39 | next_sample = 0; 40 | @(posedge clk); #1; 41 | rst = 0; 42 | 43 | @(posedge clk); #1; 44 | 45 | fork 46 | begin 47 | repeat (122000) begin 48 | // Pull next_sample every X cycles where X is a random number in [2, 9] 49 | next_sample_fetch = ($urandom() % 8) + 2; 50 | repeat (next_sample_fetch) @(posedge clk); 51 | #1; 52 | next_sample = 1; 53 | @(posedge clk); #1; 54 | $fwrite(code_file, "%d\n", code); 55 | num_samples_fetched = num_samples_fetched + 1; 56 | next_sample = 0; 57 | @(posedge clk); #1; 58 | end 59 | end 60 | begin 61 | // TODO: play with the buttons to adjust the output frequency 62 | // hint: use the num_samples_fetched integer to wait for 63 | // X samples to be fetched by the sampling thread, example below 64 | @(num_samples_fetched == 500); 65 | $display("Fetched 500 samples at time %t", $time); 66 | @(num_samples_fetched == 5000); 67 | $display("Fetched 5000 samples at time %t", $time); 68 | end 69 | join 70 | 71 | $fclose(code_file); 72 | 73 | `ifndef IVERILOG 74 | $vcdplusoff; 75 | `endif 76 | $finish(); 77 | end 78 | endmodule 79 | -------------------------------------------------------------------------------- /lab4/spec/figs/fsm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab4/spec/figs/fsm.png -------------------------------------------------------------------------------- /lab4/spec/figs/lab4figs.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab4/spec/figs/lab4figs.pptx -------------------------------------------------------------------------------- /lab4/spec/figs/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab4/spec/figs/top.png -------------------------------------------------------------------------------- /lab4/src/button_parser.v: -------------------------------------------------------------------------------- 1 | // This module instantiates the synchronizer -> debouncer -> edge detector signal chain for button inputs 2 | module button_parser #( 3 | parameter WIDTH = 1, 4 | parameter SAMPLE_CNT_MAX = 62500, 5 | parameter PULSE_CNT_MAX = 200 6 | ) ( 7 | input clk, 8 | input [WIDTH-1:0] in, 9 | output [WIDTH-1:0] out 10 | ); 11 | wire [WIDTH-1:0] synchronized_signals; 12 | wire [WIDTH-1:0] debounced_signals; 13 | 14 | synchronizer # ( 15 | .WIDTH(WIDTH) 16 | ) button_synchronizer ( 17 | .clk(clk), 18 | .async_signal(in), 19 | .sync_signal(synchronized_signals) 20 | ); 21 | 22 | debouncer # ( 23 | .WIDTH(WIDTH), 24 | .SAMPLE_CNT_MAX(SAMPLE_CNT_MAX), 25 | .PULSE_CNT_MAX(PULSE_CNT_MAX) 26 | ) button_debouncer ( 27 | .clk(clk), 28 | .glitchy_signal(synchronized_signals), 29 | .debounced_signal(debounced_signals) 30 | ); 31 | 32 | edge_detector # ( 33 | .WIDTH(WIDTH) 34 | ) button_edge_detector ( 35 | .clk(clk), 36 | .signal_in(debounced_signals), 37 | .edge_detect_pulse(out) 38 | ); 39 | endmodule 40 | -------------------------------------------------------------------------------- /lab4/src/dac.v: -------------------------------------------------------------------------------- 1 | module dac #( 2 | parameter CYCLES_PER_WINDOW = 1024, 3 | parameter CODE_WIDTH = $clog2(CYCLES_PER_WINDOW) 4 | )( 5 | input clk, 6 | input rst, 7 | input [CODE_WIDTH-1:0] code, 8 | output next_sample, 9 | output reg pwm 10 | ); 11 | assign pwm = 0; 12 | assign next_sample = 0; 13 | endmodule 14 | -------------------------------------------------------------------------------- /lab4/src/debouncer.v: -------------------------------------------------------------------------------- 1 | module debouncer #( 2 | parameter WIDTH = 1, 3 | parameter SAMPLE_CNT_MAX = 62500, 4 | parameter PULSE_CNT_MAX = 200, 5 | parameter WRAPPING_CNT_WIDTH = $clog2(SAMPLE_CNT_MAX), 6 | parameter SAT_CNT_WIDTH = $clog2(PULSE_CNT_MAX) + 1 7 | ) ( 8 | input clk, 9 | input [WIDTH-1:0] glitchy_signal, 10 | output [WIDTH-1:0] debounced_signal 11 | ); 12 | // TODO: fill in neccesary logic to implement the wrapping counter and the saturating counters 13 | // Some initial code has been provided to you, but feel free to change it however you like 14 | // One wrapping counter is required 15 | // One saturating counter is needed for each bit of glitchy_signal 16 | // You need to think of the conditions for reseting, clock enable, etc. those registers 17 | // Refer to the block diagram in the spec 18 | 19 | // Remove this line once you have created your debouncer 20 | assign debounced_signal = 0; 21 | 22 | reg [SAT_CNT_WIDTH-1:0] saturating_counter [WIDTH-1:0]; 23 | endmodule 24 | -------------------------------------------------------------------------------- /lab4/src/edge_detector.v: -------------------------------------------------------------------------------- 1 | module edge_detector #( 2 | parameter WIDTH = 1 3 | )( 4 | input clk, 5 | input [WIDTH-1:0] signal_in, 6 | output [WIDTH-1:0] edge_detect_pulse 7 | ); 8 | // TODO: implement a multi-bit edge detector that detects a rising edge of 'signal_in[x]' 9 | // and outputs a one-cycle pulse 'edge_detect_pulse[x]' at the next clock edge 10 | // Feel free to use as many number of registers you like 11 | 12 | // Remove this line once you create your edge detector 13 | assign edge_detect_pulse = 0; 14 | endmodule 15 | -------------------------------------------------------------------------------- /lab4/src/fcw_ram.v: -------------------------------------------------------------------------------- 1 | module fcw_ram( 2 | input clk, 3 | input rst, 4 | input rd_en, 5 | input wr_en, 6 | input [1:0] addr, 7 | input [23:0] d_in, 8 | output reg [23:0] d_out 9 | ); 10 | reg [23:0] ram [3:0]; 11 | 12 | always @(posedge clk) begin 13 | if (rst) begin 14 | ram[0] <= 24'd0; // replace the RAM reset values with the values you computed 15 | ram[1] <= 24'd0; 16 | ram[2] <= 24'd0; 17 | ram[3] <= 24'd0; 18 | end 19 | else if (wr_en) 20 | ram[addr] <= d_in; 21 | end 22 | 23 | always @(posedge clk) begin 24 | if (rd_en) begin 25 | d_out <= ram[addr]; 26 | end 27 | end 28 | endmodule 29 | -------------------------------------------------------------------------------- /lab4/src/fsm.v: -------------------------------------------------------------------------------- 1 | module fsm #( 2 | parameter CYCLES_PER_SECOND = 125_000_000, 3 | parameter WIDTH = $clog2(CYCLES_PER_SECOND) 4 | )( 5 | input clk, 6 | input rst, 7 | input [2:0] buttons, 8 | output [3:0] leds, 9 | output [23:0] fcw, 10 | output [1:0] leds_state 11 | ); 12 | assign leds = 0; 13 | assign fcw = 0; 14 | assign leds_state = 0; 15 | 16 | wire [1:0] addr; 17 | wire wr_en, rd_en; 18 | wire [23:0] d_in, d_out; 19 | 20 | fcw_ram notes ( 21 | .clk(clk), 22 | .rst(rst), 23 | .rd_en(rd_en), 24 | .wr_en(wr_en), 25 | .addr(addr), 26 | .d_in(d_in), 27 | .d_out(d_out) 28 | ); 29 | endmodule 30 | -------------------------------------------------------------------------------- /lab4/src/nco.v: -------------------------------------------------------------------------------- 1 | module nco( 2 | input clk, 3 | input rst, 4 | input [23:0] fcw, 5 | input next_sample, 6 | output [9:0] code 7 | ); 8 | assign code = 0; 9 | endmodule 10 | -------------------------------------------------------------------------------- /lab4/src/sine.bin: -------------------------------------------------------------------------------- 1 | 1000000000 2 | 1000001100 3 | 1000011001 4 | 1000100101 5 | 1000110010 6 | 1000111110 7 | 1001001011 8 | 1001010111 9 | 1001100011 10 | 1001110000 11 | 1001111100 12 | 1010001000 13 | 1010010100 14 | 1010100000 15 | 1010101100 16 | 1010111000 17 | 1011000011 18 | 1011001111 19 | 1011011010 20 | 1011100110 21 | 1011110001 22 | 1011111100 23 | 1100000111 24 | 1100010001 25 | 1100011100 26 | 1100100110 27 | 1100110000 28 | 1100111010 29 | 1101000100 30 | 1101001110 31 | 1101010111 32 | 1101100001 33 | 1101101010 34 | 1101110010 35 | 1101111011 36 | 1110000011 37 | 1110001011 38 | 1110010011 39 | 1110011011 40 | 1110100010 41 | 1110101001 42 | 1110110000 43 | 1110110111 44 | 1110111101 45 | 1111000011 46 | 1111001001 47 | 1111001110 48 | 1111010100 49 | 1111011001 50 | 1111011101 51 | 1111100010 52 | 1111100110 53 | 1111101001 54 | 1111101101 55 | 1111110000 56 | 1111110011 57 | 1111110110 58 | 1111111000 59 | 1111111010 60 | 1111111100 61 | 1111111101 62 | 1111111110 63 | 1111111111 64 | 1111111111 65 | 1111111111 66 | 1111111111 67 | 1111111111 68 | 1111111110 69 | 1111111101 70 | 1111111100 71 | 1111111010 72 | 1111111000 73 | 1111110110 74 | 1111110011 75 | 1111110000 76 | 1111101101 77 | 1111101001 78 | 1111100110 79 | 1111100010 80 | 1111011101 81 | 1111011001 82 | 1111010100 83 | 1111001110 84 | 1111001001 85 | 1111000011 86 | 1110111101 87 | 1110110111 88 | 1110110000 89 | 1110101001 90 | 1110100010 91 | 1110011011 92 | 1110010011 93 | 1110001011 94 | 1110000011 95 | 1101111011 96 | 1101110010 97 | 1101101010 98 | 1101100001 99 | 1101010111 100 | 1101001110 101 | 1101000100 102 | 1100111010 103 | 1100110000 104 | 1100100110 105 | 1100011100 106 | 1100010001 107 | 1100000111 108 | 1011111100 109 | 1011110001 110 | 1011100110 111 | 1011011010 112 | 1011001111 113 | 1011000011 114 | 1010111000 115 | 1010101100 116 | 1010100000 117 | 1010010100 118 | 1010001000 119 | 1001111100 120 | 1001110000 121 | 1001100011 122 | 1001010111 123 | 1001001011 124 | 1000111110 125 | 1000110010 126 | 1000100101 127 | 1000011001 128 | 1000001100 129 | 1000000000 130 | 0111110011 131 | 0111100110 132 | 0111011010 133 | 0111001101 134 | 0111000001 135 | 0110110100 136 | 0110101000 137 | 0110011100 138 | 0110001111 139 | 0110000011 140 | 0101110111 141 | 0101101011 142 | 0101011111 143 | 0101010011 144 | 0101000111 145 | 0100111100 146 | 0100110000 147 | 0100100101 148 | 0100011001 149 | 0100001110 150 | 0100000011 151 | 0011111000 152 | 0011101110 153 | 0011100011 154 | 0011011001 155 | 0011001111 156 | 0011000101 157 | 0010111011 158 | 0010110001 159 | 0010101000 160 | 0010011110 161 | 0010010101 162 | 0010001101 163 | 0010000100 164 | 0001111100 165 | 0001110100 166 | 0001101100 167 | 0001100100 168 | 0001011101 169 | 0001010110 170 | 0001001111 171 | 0001001000 172 | 0001000010 173 | 0000111100 174 | 0000110110 175 | 0000110001 176 | 0000101011 177 | 0000100110 178 | 0000100010 179 | 0000011101 180 | 0000011001 181 | 0000010110 182 | 0000010010 183 | 0000001111 184 | 0000001100 185 | 0000001001 186 | 0000000111 187 | 0000000101 188 | 0000000011 189 | 0000000010 190 | 0000000001 191 | 0000000000 192 | 0000000000 193 | 0000000000 194 | 0000000000 195 | 0000000000 196 | 0000000001 197 | 0000000010 198 | 0000000011 199 | 0000000101 200 | 0000000111 201 | 0000001001 202 | 0000001100 203 | 0000001111 204 | 0000010010 205 | 0000010110 206 | 0000011001 207 | 0000011101 208 | 0000100010 209 | 0000100110 210 | 0000101011 211 | 0000110001 212 | 0000110110 213 | 0000111100 214 | 0001000010 215 | 0001001000 216 | 0001001111 217 | 0001010110 218 | 0001011101 219 | 0001100100 220 | 0001101100 221 | 0001110100 222 | 0001111100 223 | 0010000100 224 | 0010001101 225 | 0010010101 226 | 0010011110 227 | 0010101000 228 | 0010110001 229 | 0010111011 230 | 0011000101 231 | 0011001111 232 | 0011011001 233 | 0011100011 234 | 0011101110 235 | 0011111000 236 | 0100000011 237 | 0100001110 238 | 0100011001 239 | 0100100101 240 | 0100110000 241 | 0100111100 242 | 0101000111 243 | 0101010011 244 | 0101011111 245 | 0101101011 246 | 0101110111 247 | 0110000011 248 | 0110001111 249 | 0110011100 250 | 0110101000 251 | 0110110100 252 | 0111000001 253 | 0111001101 254 | 0111011010 255 | 0111100110 256 | 0111110011 257 | -------------------------------------------------------------------------------- /lab4/src/sq_wave_gen.v: -------------------------------------------------------------------------------- 1 | module sq_wave_gen #( 2 | parameter STEP = 10 3 | )( 4 | input clk, 5 | input rst, 6 | input next_sample, 7 | input [2:0] buttons, 8 | output [9:0] code, 9 | output [3:0] leds 10 | ); 11 | assign code = 0; 12 | assign leds = 0; 13 | endmodule 14 | -------------------------------------------------------------------------------- /lab4/src/synchronizer.v: -------------------------------------------------------------------------------- 1 | module synchronizer #(parameter WIDTH = 1) ( 2 | input [WIDTH-1:0] async_signal, 3 | input clk, 4 | output [WIDTH-1:0] sync_signal 5 | ); 6 | // TODO: Create your 2 flip-flop synchronizer here 7 | // This module takes in a vector of WIDTH-bit asynchronous 8 | // (from different clock domain or not clocked, such as button press) signals 9 | // and should output a vector of WIDTH-bit synchronous signals 10 | // that are synchronized to the input clk 11 | 12 | // Remove this line once you create your synchronizer 13 | assign sync_signal = 0; 14 | endmodule 15 | -------------------------------------------------------------------------------- /lab4/src/z1top.v: -------------------------------------------------------------------------------- 1 | `define CLOCK_FREQ 125_000_000 2 | 3 | module z1top ( 4 | input CLK_125MHZ_FPGA, 5 | input [3:0] BUTTONS, 6 | input [1:0] SWITCHES, 7 | output [5:0] LEDS, 8 | output AUD_PWM, 9 | output AUD_SD 10 | ); 11 | // Button parser test circuit 12 | // Sample the button signal every 500us 13 | localparam integer B_SAMPLE_CNT_MAX = $rtoi(0.0005 * `CLOCK_FREQ); 14 | // The button is considered 'pressed' after 100ms of continuous pressing 15 | localparam integer B_PULSE_CNT_MAX = $rtoi(0.100 / 0.0005); 16 | 17 | wire [3:0] buttons_pressed; 18 | wire [2:0] buttons_sq_wave, buttons_fsm; 19 | button_parser #( 20 | .WIDTH(4), 21 | .SAMPLE_CNT_MAX(B_SAMPLE_CNT_MAX), 22 | .PULSE_CNT_MAX(B_PULSE_CNT_MAX) 23 | ) bp ( 24 | .clk(CLK_125MHZ_FPGA), 25 | .in(BUTTONS), 26 | .out(buttons_pressed) 27 | ); 28 | 29 | wire next_sample; 30 | wire [9:0] code, sq_wave_code, nco_code; 31 | wire [3:0] fsm_leds, sq_wave_leds; 32 | wire [2:0] fsm_buttons, sq_wave_buttons; 33 | wire [23:0] fcw; 34 | wire [1:0] addr; 35 | wire [23:0] d_in; 36 | wire wr_en; 37 | wire [1:0] switches_sync; 38 | wire rst; 39 | 40 | synchronizer #(.WIDTH(2)) switch_sync (.clk(CLK_125MHZ_FPGA), .async_signal(SWITCHES), .sync_signal(switches_sync)); 41 | 42 | assign AUD_SD = switches_sync[1]; // 1 = audio enabled 43 | assign LEDS[3:0] = switches_sync[0] ? fsm_leds : sq_wave_leds; 44 | assign code = switches_sync[0] ? nco_code : sq_wave_code; 45 | assign rst = buttons_pressed[3]; 46 | assign sq_wave_buttons = switches_sync[0] ? 3'b000 : buttons_pressed[2:0]; 47 | assign fsm_buttons = switches_sync[0] ? buttons_pressed[2:0] : 3'b000; 48 | 49 | dac #( 50 | .CYCLES_PER_WINDOW(1024) 51 | ) dac ( 52 | .clk(CLK_125MHZ_FPGA), 53 | .rst(rst), 54 | .code(code), 55 | .next_sample(next_sample), 56 | .pwm(AUD_PWM) 57 | ); 58 | 59 | sq_wave_gen gen ( 60 | .clk(CLK_125MHZ_FPGA), 61 | .rst(rst), 62 | .next_sample(next_sample), 63 | .buttons(sq_wave_buttons), 64 | .code(sq_wave_code), 65 | .leds(sq_wave_leds) 66 | ); 67 | 68 | nco nco ( 69 | .clk(CLK_125MHZ_FPGA), 70 | .rst(rst), 71 | .fcw(fcw), 72 | .next_sample(next_sample), 73 | .code(nco_code) 74 | ); 75 | 76 | fsm fsm ( 77 | .clk(CLK_125MHZ_FPGA), 78 | .rst(rst), 79 | .buttons(fsm_buttons), 80 | .leds(fsm_leds), 81 | .leds_state(LEDS[5:4]), 82 | .fcw(fcw) 83 | ); 84 | endmodule 85 | -------------------------------------------------------------------------------- /lab4/src/z1top.xdc: -------------------------------------------------------------------------------- 1 | ## Source: https://reference.digilentinc.com/_media/reference/programmable-logic/pynq-z1/pynq-z1_c.zip 2 | ## 3 | 4 | ## Clock signal 125 MHz 5 | 6 | set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { CLK_125MHZ_FPGA }]; 7 | create_clock -add -name clk_125mhz_fpga -period 8.00 -waveform {0 4} [get_ports { CLK_125MHZ_FPGA }]; 8 | 9 | ## RGB LEDs 10 | 11 | set_property -dict { PACKAGE_PIN L15 IOSTANDARD LVCMOS33 } [get_ports { LEDS[4] }]; 12 | set_property -dict { PACKAGE_PIN M15 IOSTANDARD LVCMOS33 } [get_ports { LEDS[5] }]; 13 | 14 | ## LEDs 15 | 16 | set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {LEDS[0]}] 17 | set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports {LEDS[1]}] 18 | set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports {LEDS[2]}] 19 | set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports {LEDS[3]}] 20 | 21 | ## Buttons 22 | 23 | set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports {BUTTONS[0]}] 24 | set_property -dict {PACKAGE_PIN D20 IOSTANDARD LVCMOS33} [get_ports {BUTTONS[1]}] 25 | set_property -dict {PACKAGE_PIN L20 IOSTANDARD LVCMOS33} [get_ports {BUTTONS[2]}] 26 | set_property -dict {PACKAGE_PIN L19 IOSTANDARD LVCMOS33} [get_ports {BUTTONS[3]}] 27 | 28 | ## Switches 29 | 30 | set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports {SWITCHES[0]}] 31 | set_property -dict {PACKAGE_PIN M19 IOSTANDARD LVCMOS33} [get_ports {SWITCHES[1]}] 32 | 33 | ## Audio Out 34 | set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { AUD_PWM }]; 35 | set_property -dict { PACKAGE_PIN T17 IOSTANDARD LVCMOS33 } [get_ports { AUD_SD }]; 36 | -------------------------------------------------------------------------------- /lab5/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefrag 2 | -------------------------------------------------------------------------------- /lab5/sim/echo_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ps 2 | 3 | module echo_tb(); 4 | reg clk, rst; 5 | localparam CLOCK_FREQ = 125_000_000; 6 | localparam CLOCK_PERIOD = 1_000_000_000 / CLOCK_FREQ; 7 | localparam BAUD_RATE = 115_200; 8 | localparam BAUD_PERIOD = 1_000_000_000 / BAUD_RATE; // 8680.55 ns 9 | 10 | localparam integer SYMBOL_EDGE_TIME = CLOCK_FREQ / BAUD_RATE; 11 | 12 | localparam CHAR0 = 8'h41; // ~ 'A' 13 | localparam NUM_CHARS = 60; 14 | 15 | initial clk = 0; 16 | always #(CLOCK_PERIOD / 2) clk = ~clk; 17 | 18 | // host --> (serial_in) z1top (serial_out) --> host (echoed) 19 | 20 | reg serial_in; 21 | wire serial_out; 22 | 23 | z1top #( 24 | .CLOCK_FREQ(CLOCK_FREQ), 25 | .BAUD_RATE(BAUD_RATE), 26 | .B_SAMPLE_CNT_MAX(5), 27 | .B_PULSE_CNT_MAX(5) 28 | ) DUT ( 29 | .CLK_125MHZ_FPGA(clk), 30 | .BUTTONS({3'b0, rst}), 31 | .SWITCHES(2'b0), 32 | .LEDS(), 33 | .AUD_PWM(), 34 | .AUD_SD(), 35 | .FPGA_SERIAL_RX(serial_in), 36 | .FPGA_SERIAL_TX(serial_out) 37 | ); 38 | 39 | integer i, j, c, c1, c2; 40 | reg [31:0] cycle_cnt; 41 | integer num_mismatches = 0; 42 | 43 | // this holds characters sent by the host to the serial line 44 | reg [7:0] chars_from_host [NUM_CHARS-1:0]; 45 | // this holds characters received by the host from the serial line 46 | reg [9:0] chars_to_host [NUM_CHARS-1:0]; 47 | 48 | // initialize test vectors 49 | initial begin 50 | #0; 51 | for (c = 0; c < NUM_CHARS; c = c + 1) begin 52 | chars_from_host[c] = CHAR0 + c; 53 | end 54 | end 55 | 56 | always @(posedge clk) begin 57 | if (rst === 1'b1) 58 | cycle_cnt <= 0; 59 | else 60 | cycle_cnt <= cycle_cnt + 1; 61 | end 62 | 63 | // Host off-chip UART --> FPGA on-chip UART (receiver) 64 | // The host (testbench) sends a character to the CPU via the serial line 65 | task host_to_fpga; 66 | begin 67 | #0; 68 | serial_in = 1; 69 | 70 | for (c1 = 0; c1 < NUM_CHARS; c1 = c1 + 1) begin 71 | // Start bit 72 | serial_in = 0; 73 | #(BAUD_PERIOD); 74 | // Data bits (payload) 75 | for (i = 0; i < 8; i = i + 1) begin 76 | serial_in = chars_from_host[c1][i]; 77 | #(BAUD_PERIOD); 78 | end 79 | // Stop bit 80 | serial_in = 1; 81 | #(BAUD_PERIOD); 82 | 83 | $display("[time %t, sim. cycle %d] [Host (tb) --> FPGA_SERIAL_RX] Sent char 8'h%h (= %s)", 84 | $time, cycle_cnt, chars_from_host[c1], chars_from_host[c1]); 85 | end 86 | end 87 | endtask 88 | 89 | // Host off-chip UART <-- FPGA on-chip UART (transmitter) 90 | // The host (testbench) expects to receive a character from the CPU via the serial line (echoed) 91 | task fpga_to_host; 92 | begin 93 | for (c2 = 0; c2 < NUM_CHARS; c2 = c2 + 1) begin 94 | // Wait until serial_out is LOW (start of transaction) 95 | wait (serial_out === 1'b0); 96 | 97 | for (j = 0; j < 10; j = j + 1) begin 98 | #(BAUD_PERIOD / 2); 99 | chars_to_host[c2][j] = serial_out; 100 | #(BAUD_PERIOD / 2); 101 | end 102 | 103 | $display("[time %t, sim. cycle %d] [Host (tb) <-- FPGA_SERIAL_TX] Got char: start_bit=%b, payload=8'h%h (= %s), stop_bit=%b", 104 | $time, cycle_cnt, 105 | chars_to_host[c2][0], 106 | chars_to_host[c2][8:1], chars_to_host[c2][8:1], 107 | chars_to_host[c2][9]); 108 | end 109 | end 110 | endtask 111 | 112 | task case_inverter; 113 | input [7:0] in_char; 114 | output [7:0] out_char; 115 | begin 116 | if (in_char >= "a" && in_char <= "z") 117 | out_char = in_char - 8'd32; 118 | else if (in_char >= "A" && in_char <= "Z") 119 | out_char = in_char + 8'd32; 120 | else 121 | out_char = in_char; 122 | end 123 | endtask 124 | 125 | reg [7:0] cinv_char_to_host; 126 | 127 | initial begin 128 | #0; 129 | `ifdef IVERILOG 130 | $dumpfile("echo_tb.fst"); 131 | $dumpvars(0, echo_tb); 132 | `endif 133 | `ifndef IVERILOG 134 | $vcdpluson; 135 | `endif 136 | 137 | rst = 1'b1; 138 | 139 | // Hold reset for a while 140 | repeat (40) @(posedge clk); 141 | 142 | rst = 1'b0; 143 | 144 | // Delay for some time 145 | repeat (10) @(posedge clk); 146 | 147 | // Launch the tasks in parallel 148 | fork 149 | begin 150 | host_to_fpga(); 151 | end 152 | begin 153 | fpga_to_host(); 154 | end 155 | join 156 | 157 | // Check results 158 | for (c = 0; c < NUM_CHARS; c = c + 1) begin 159 | case_inverter(chars_to_host[c][8:1], cinv_char_to_host); 160 | if (chars_from_host[c] !== cinv_char_to_host) begin 161 | $error("Mismatches at char %d: char_from_host=%h (= %s), char_to_host=%h (= %s)", 162 | c, chars_from_host[c], chars_from_host[c], 163 | cinv_char_to_host, cinv_char_to_host); 164 | num_mismatches = num_mismatches + 1; 165 | end 166 | end 167 | 168 | if (num_mismatches > 0) 169 | $display("Tests failed"); 170 | else 171 | $display("Tests passed!"); 172 | 173 | $finish(); 174 | #100; 175 | end 176 | 177 | initial begin 178 | repeat (2 * SYMBOL_EDGE_TIME * 10 * NUM_CHARS) @(posedge clk); 179 | $error("Timeout!"); 180 | $fatal(); 181 | end 182 | 183 | endmodule 184 | -------------------------------------------------------------------------------- /lab5/sim/echo_tb.vcd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab5/sim/echo_tb.vcd -------------------------------------------------------------------------------- /lab5/sim/simple_echo_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/100ps 2 | 3 | `define CLOCK_PERIOD 8 4 | `define CLOCK_FREQ 125_000_000 5 | `define BAUD_RATE 115_200 6 | `define B_SAMPLE_CNT_MAX 5 7 | `define B_PULSE_CNT_MAX 5 8 | 9 | /* 10 | This is a system level testbench that instantiates z1top (the FPGA design) and an off-chip UART which communicates 11 | with the FPGA design using the RX and TX serial lines. The testbench can control the receiver and transmitter of the 12 | off-chip UART with their respective ready/valid interfaces. 13 | 14 | In this testbench, we use the off-chip UART to send a character (ASCII 'A') to the FPGA's on-chip UART (in z1top). 15 | Then, the state machine in z1top gets the received character from the on-chip UART, manipulates it (by reversing its case), 16 | and sends it back to the off-chip UART using the on-chip UART's transmitter. We expect that the received character by the 17 | off-chip UART at the end of this test will be a lower case ASCII 'a'. 18 | */ 19 | module simple_echo_tb(); 20 | // Generate 125 MHz clock 21 | reg clk = 0; 22 | always #(`CLOCK_PERIOD/2) clk = ~clk; 23 | 24 | // I/O of z1top 25 | wire FPGA_SERIAL_RX, FPGA_SERIAL_TX; 26 | reg reset; 27 | 28 | wire [5:0] leds; 29 | // Our FPGA design 30 | z1top #( 31 | .CLOCK_FREQ(`CLOCK_FREQ), 32 | .BAUD_RATE(`BAUD_RATE), 33 | .B_SAMPLE_CNT_MAX(`B_SAMPLE_CNT_MAX), 34 | .B_PULSE_CNT_MAX(`B_PULSE_CNT_MAX) 35 | ) top ( 36 | .CLK_125MHZ_FPGA(clk), 37 | .BUTTONS({3'd0, reset}), 38 | .SWITCHES(2'd0), 39 | .LEDS(leds), 40 | .FPGA_SERIAL_RX(FPGA_SERIAL_RX), 41 | .FPGA_SERIAL_TX(FPGA_SERIAL_TX) 42 | ); 43 | 44 | // I/O of the off-chip UART 45 | reg [7:0] data_in; 46 | reg data_in_valid; 47 | wire data_in_ready; 48 | wire [7:0] data_out; 49 | wire data_out_valid; 50 | reg data_out_ready; 51 | 52 | // The off-chip UART (on your desktop/workstation computer) 53 | uart # ( 54 | .CLOCK_FREQ(`CLOCK_FREQ), 55 | .BAUD_RATE(`BAUD_RATE) 56 | ) off_chip_uart ( 57 | .clk(clk), 58 | .reset(reset), 59 | .data_in(data_in), 60 | .data_in_valid(data_in_valid), 61 | .data_in_ready(data_in_ready), 62 | .data_out(data_out), 63 | .data_out_valid(data_out_valid), 64 | .data_out_ready(data_out_ready), 65 | .serial_in(FPGA_SERIAL_TX), // Note these serial connections are the opposite of the connections to z1top 66 | .serial_out(FPGA_SERIAL_RX) 67 | ); 68 | 69 | reg done = 0; 70 | initial begin 71 | `ifndef IVERILOG 72 | $vcdpluson; 73 | `endif 74 | `ifdef IVERILOG 75 | $dumpfile("simple_echo_tb.fst"); 76 | $dumpvars(0, simple_echo_tb); 77 | `endif 78 | reset = 1'b0; 79 | data_in = 8'h41; // Represents the character 'A' in ASCII 80 | data_in_valid = 1'b0; 81 | data_out_ready = 1'b0; 82 | repeat (2) @(posedge clk); #1; 83 | 84 | // Pulse the reset signal long enough to be detected by the debouncer in z1top 85 | reset = 1'b1; 86 | repeat (40) @(posedge clk); #1; 87 | reset = 1'b0; 88 | 89 | //Reset on FPGA should occur on positive edge of reset for 1 cycle 90 | 91 | fork 92 | begin 93 | // Wait until the off-chip UART transmitter is ready to transmit 94 | while (!data_in_ready) @(posedge clk); #1; 95 | 96 | // Once the off-chip UART transmitter is ready, pulse data_in_valid to tell it that 97 | // we have valid data that we want it to send over the serial line 98 | // Will set this on negedge to make semantics more clear 99 | @(negedge clk); #1; 100 | data_in_valid = 1'b1; 101 | @(negedge clk); #1; 102 | data_in_valid = 1'b0; 103 | $display("off-chip UART about to transmit: %h/%c to the on-chip UART", data_in, data_in); 104 | 105 | // Now the off-chip UART transmitter should be sending the data across FPGA_SERIAL_RX 106 | 107 | // Once all the data reaches the on-chip UART, it should set top/on_chip_uart/data_out_valid high 108 | while (!top.on_chip_uart.data_out_valid) @(posedge clk); #1; 109 | $display("on-chip UART received: %h from the off-chip UART", top.on_chip_uart.data_out); 110 | 111 | // Then the state machine in z1top should pulse top/on_chip_uart/data_out_ready high and send the data 112 | // it received back through the on-chip UART transmitter. 113 | while (!top.on_chip_uart.data_in_valid) @(posedge clk); #1; 114 | $display("on-chip UART about to transmit: %h to the off-chip UART", top.on_chip_uart.data_in); 115 | 116 | // Finally, when the data is echoed back to the off-chip UART, data_out_valid should go high. Now is when 117 | // the off chip UART can read the data it received and print it out to the user 118 | while (!data_out_valid) @(posedge clk); #1; 119 | $display("off-chip UART received: %h/%c from on-chip UART", data_out, data_out); 120 | data_out_ready = 1'b1; 121 | @(posedge clk); #1; 122 | data_out_ready = 1'b0; 123 | done = 1; 124 | end 125 | begin 126 | repeat (35000) @(posedge clk); 127 | if (!done) begin 128 | $error("Failure: timing out"); 129 | $fatal(); 130 | end 131 | end 132 | join 133 | 134 | repeat (100) @(posedge clk); 135 | $display("%h/%c should have been sent and %h/%c echoed back", 8'h41, 8'h41, 8'h61, 8'h61); 136 | `ifndef IVERILOG 137 | $vcdplusoff; 138 | `endif 139 | $finish(); 140 | end 141 | endmodule 142 | -------------------------------------------------------------------------------- /lab5/sim/uart2uart_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ps 2 | 3 | `define CLOCK_PERIOD 8 4 | `define CLOCK_FREQ 125_000_000 5 | `define BAUD_RATE 115_200 6 | 7 | /* 8 | In this testbench, we instantiate 2 UARTs. They are connected via the serial lines (FPGA_SERIAL_RX/TX). 9 | Our testbench is given access to the 1st UART's transmitter's ready/valid interface and the 2nd UART's 10 | receiver's ready/valid interface. The testbench then directs the transmitter to send a character and then 11 | waits for the receiver to acknowlege that data has been sent to it. It then reads the data from the receiver 12 | and compares it to what was transmitted. 13 | */ 14 | module uart2uart_tb(); 15 | // Generate 125 MHz clock 16 | reg clk = 0; 17 | always #(`CLOCK_PERIOD/2) clk = ~clk; 18 | 19 | // I/O of off-chip and on-chip UART 20 | wire FPGA_SERIAL_RX, FPGA_SERIAL_TX; 21 | reg reset; 22 | 23 | reg [7:0] data_in; 24 | reg data_in_valid; 25 | wire data_in_ready; 26 | 27 | wire [7:0] data_out; 28 | wire data_out_valid; 29 | reg data_out_ready; 30 | 31 | uart # ( 32 | .CLOCK_FREQ(`CLOCK_FREQ), 33 | .BAUD_RATE(`BAUD_RATE) 34 | ) off_chip_uart ( 35 | .clk(clk), 36 | .reset(reset), 37 | .data_in(data_in), 38 | .data_in_valid(data_in_valid), 39 | .data_in_ready(data_in_ready), 40 | .data_out(), // We aren't using the receiver of the off-chip UART, only the transmitter 41 | .data_out_valid(), 42 | .data_out_ready(1'b0), 43 | .serial_in(FPGA_SERIAL_RX), 44 | .serial_out(FPGA_SERIAL_TX) 45 | ); 46 | 47 | uart # ( 48 | .CLOCK_FREQ(`CLOCK_FREQ), 49 | .BAUD_RATE(`BAUD_RATE) 50 | ) on_chip_uart ( 51 | .clk(clk), 52 | .reset(reset), 53 | .data_in(8'd0), // We aren't using the transmitter of the on-chip UART, only the receiver 54 | .data_in_valid(1'b0), 55 | .data_in_ready(), 56 | .data_out(data_out), 57 | .data_out_valid(data_out_valid), 58 | .data_out_ready(data_out_ready), 59 | .serial_in(FPGA_SERIAL_TX), // Notice these lines are connected opposite to the off_chip_uart 60 | .serial_out(FPGA_SERIAL_RX) 61 | ); 62 | 63 | reg done = 0; 64 | initial begin 65 | `ifdef IVERILOG 66 | $dumpfile("uart2uart_tb.fst"); 67 | $dumpvars(0, uart2uart_tb); 68 | `endif 69 | `ifndef IVERILOG 70 | $vcdpluson; 71 | `endif 72 | reset = 1'b0; 73 | data_in = 8'd0; 74 | data_in_valid = 1'b0; 75 | data_out_ready = 1'b0; 76 | repeat (2) @(posedge clk); #1; 77 | 78 | // Reset the UARTs 79 | reset = 1'b1; 80 | @(posedge clk); #1; 81 | reset = 1'b0; 82 | 83 | fork 84 | begin 85 | // Wait until the off_chip_uart's transmitter is ready 86 | while (data_in_ready == 1'b0) @(posedge clk); #1; 87 | 88 | // Send a character to the off chip UART's transmitter to transmit over the serial line 89 | data_in = 8'h21; 90 | data_in_valid = 1'b1; 91 | @(posedge clk); #1; 92 | data_in_valid = 1'b0; 93 | 94 | // Now, the transmitter should be sending the data_in over the FPGA_SERIAL_TX line to the on chip UART 95 | 96 | // We wait until the on chip UART's receiver indicates that is has valid data it has received 97 | while (data_out_valid == 1'b0) @(posedge clk); #1; 98 | 99 | // Now, data_out of the on chip UART should contain the data that was sent to it by the off chip UART 100 | if (data_out !== 8'h21) begin 101 | $error("Failure 1: on chip UART got data: %h, but expected: %h", data_out, 8'h21); 102 | end 103 | 104 | // If we wait a few more clock cycles, the data should still be held by the receiver 105 | repeat (10) @(posedge clk); #1; 106 | if (data_out !== 8'h21) begin 107 | $error("Failure 2: on chip UART got correct data, but it didn't hold data_out until data_out_ready was asserted"); 108 | end 109 | 110 | // At this point, the off chip UART's transmitter should be idle and the FPGA_SERIAL_TX line should be in the idle state 111 | if (FPGA_SERIAL_TX !== 1'b1) begin 112 | $error("Failure 3: FPGA_SERIAL_TX was not high when the off chip UART's transmitter should be idle"); 113 | end 114 | 115 | // Now, if we assert data_out_ready to the on chip UART's receiver, it should pull its data_out_valid signal low 116 | data_out_ready = 1'b1; 117 | @(posedge clk); #1; 118 | data_out_ready = 1'b0; 119 | @(posedge clk); #1; 120 | if (data_out_valid == 1'b1) begin 121 | $error("Failure 4: on chip UART didn't clear data_out_valid when data_out_ready was asserted"); 122 | end 123 | done = 1; 124 | end 125 | begin 126 | repeat (25000) @(posedge clk); 127 | if (!done) begin 128 | $error("Failure: timing out"); 129 | $fatal(); 130 | end 131 | end 132 | join 133 | 134 | repeat (20) @(posedge clk); 135 | $display("Test finished"); 136 | `ifndef IVERILOG 137 | $vcdplusoff; 138 | `endif 139 | $finish(); 140 | end 141 | endmodule 142 | -------------------------------------------------------------------------------- /lab5/sim/uart_transmitter_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ps 2 | 3 | // UART_Transmitter is essentially a reverse of UART_Receiver 4 | module uart_transmitter_tb(); 5 | localparam CLOCK_FREQ = 125_000_000; 6 | localparam CLOCK_PERIOD = 1_000_000_000 / CLOCK_FREQ; 7 | localparam BAUD_RATE = 115_200; 8 | localparam integer BAUD_PERIOD = 1_000_000_000 / BAUD_RATE; // 8680.55 ns 9 | 10 | localparam CHAR0 = 8'h61; // ~ 'a' 11 | localparam NUM_CHARS = 16; 12 | 13 | localparam INPUT_DELAY = 1000; 14 | 15 | reg clk, rst; 16 | initial clk = 0; 17 | always #(CLOCK_PERIOD / 2) clk = ~clk; 18 | 19 | // producer (testbench) --> (data_in R/V) uart_transmitter (serial_out) --> host 20 | 21 | wire [7:0] data_in; 22 | reg data_in_valid; 23 | wire data_in_ready; 24 | wire serial_out; 25 | 26 | uart_transmitter #( 27 | .CLOCK_FREQ(CLOCK_FREQ), 28 | .BAUD_RATE(BAUD_RATE) 29 | ) DUT ( 30 | .clk(clk), 31 | .reset(rst), 32 | 33 | .data_in(data_in), // input 34 | .data_in_valid(data_in_valid), // input 35 | .data_in_ready(data_in_ready), // output 36 | .serial_out(serial_out) // output 37 | ); 38 | 39 | integer i, j, c; 40 | 41 | // this holds characters sent by the UART_transmitter to the host via serial line 42 | // including the start and stop bits 43 | reg [10-1:0] chars_to_host [NUM_CHARS-1:0]; 44 | // this holds characters received from data_in via the Handshake interface 45 | reg [7:0] chars_from_data_in [NUM_CHARS-1:0]; 46 | 47 | // initialize test vectors 48 | initial begin 49 | #0; 50 | for (c = 0; c < NUM_CHARS; c = c + 1) begin 51 | chars_from_data_in[c] = CHAR0 + c; 52 | end 53 | end 54 | 55 | reg [31:0] cnt; 56 | 57 | assign data_in = chars_from_data_in[cnt]; 58 | reg data_in_fired; 59 | 60 | always @(posedge clk) begin 61 | if (rst) begin 62 | cnt <= 0; 63 | end 64 | else begin 65 | if (data_in_fired === 1'b1) begin 66 | data_in_fired <= 1'b0; 67 | if (data_in_ready === 1'b1) begin 68 | $error("[time %t] Failed: data_in_ready should go LOW in the next clock edge after firing data_in\n", $time); 69 | //$fatal(); 70 | end 71 | end 72 | else if (data_in_valid === 1'b1 && data_in_ready === 1'b1) begin 73 | data_in_fired <= 1'b1; 74 | cnt <= cnt + 1; 75 | $display("[time %t] [data_in] Sent char: 8'h%h (=%s)", $time, data_in, data_in); 76 | end 77 | end 78 | end 79 | 80 | initial begin 81 | data_in_valid = 1'b0; 82 | 83 | repeat (10) @(posedge clk); 84 | 85 | // This for-loop emulates the producer 86 | // It sends new character (data_in) to the uart_transmitter via the 87 | // handshake interface as long as the uart_transmitter is ready 88 | for (j = 0; j < NUM_CHARS; j = j + 1) begin 89 | // wait until uart_transmitter is ready to get new character 90 | wait (data_in_ready === 1'b1); 91 | 92 | // Add some delay between successive characters sent to uart 93 | #(INPUT_DELAY); 94 | 95 | // the producer has valid data 96 | @(negedge clk); 97 | data_in_valid = 1'b1; 98 | 99 | // the uart_transmitter should have received the character at this posedge clk 100 | // since valid and ready are both HIGH 101 | // @(posedge clk); 102 | 103 | @(negedge clk); 104 | data_in_valid = 1'b0; // pull valid LOW to make life harder 105 | 106 | end 107 | end 108 | 109 | integer num_mismatches = 0; 110 | 111 | initial begin 112 | #0; 113 | `ifdef IVERILOG 114 | $dumpfile("uart_transmitter_tb.fst"); 115 | $dumpvars(0, uart_transmitter_tb); 116 | `endif 117 | `ifndef IVERILOG 118 | $vcdpluson; 119 | `endif 120 | 121 | rst = 1'b1; 122 | cnt = 0; 123 | 124 | // Hold reset for a while 125 | repeat (10) @(posedge clk); 126 | 127 | @(negedge clk); 128 | rst = 1'b0; 129 | 130 | if (data_in_ready === 1'b0) begin 131 | $error("[time %t] Failed: data_in_ready should not be LOW after reset", $time); 132 | repeat (5) @(posedge clk); 133 | $fatal(); 134 | end 135 | 136 | if (serial_out !== 1) begin 137 | $error("[time %t] Failed: serial_out should stay HIGH if there is no data_in to receive by handshake!", $time); 138 | repeat (5) @(posedge clk); 139 | $fatal(); 140 | end 141 | 142 | // Delay for some time 143 | repeat (100) @(posedge clk); 144 | 145 | // This for-loop checks the output of the serial interface 146 | // to ensure that the serialized output bits match the characters sent 147 | // by the producer (through the uart_transmitter) 148 | for (c = 0; c < NUM_CHARS; c = c + 1) begin 149 | // Wait until serial_out is LOW (start of transaction) 150 | wait (serial_out === 1'b0); 151 | 152 | for (i = 0; i < 10; i = i + 1) begin 153 | // sample output half-way through the baud period to avoid tricky edge cases 154 | #(BAUD_PERIOD / 2); 155 | chars_to_host[c][i] = serial_out; 156 | #(BAUD_PERIOD / 2); 157 | end 158 | $display("[time %t] [serial_out] Got char: start_bit=%b, payload=8'h%h (=%s), stop_bit=%b", 159 | $time, 160 | chars_to_host[c][0], 161 | chars_to_host[c][8:1], chars_to_host[c][8:1], 162 | chars_to_host[c][9]); 163 | end 164 | 165 | // Delay for some time 166 | repeat (10) @(posedge clk); 167 | 168 | // Check results 169 | for (c = 0; c < NUM_CHARS; c = c + 1) begin 170 | if (chars_from_data_in[c] !== chars_to_host[c][8:1]) begin 171 | $error("Mismatches at char %d: char_to_host=%h (=%s), char_from_data_in=%h (=%s)", 172 | c, 173 | chars_to_host[c][8:1], chars_to_host[c][8:1], 174 | chars_from_data_in[c], chars_from_data_in[c]); 175 | num_mismatches = num_mismatches + 1; 176 | end 177 | 178 | if (chars_to_host[c][0] !== 0) 179 | $error("[char #%d] Failed: Start bit is expected to be LOW!", c); 180 | if (chars_to_host[c][9] !== 1) 181 | $error("[char #%d] Failed: End bit is expected to HIGH!", c); 182 | end 183 | 184 | if (serial_out !== 1) begin 185 | $error("[time %t] Failed: serial_out should stay HIGH if there is no data_in to receive by handshake!", $time); 186 | //$fatal(); 187 | end 188 | 189 | if (num_mismatches > 0) 190 | $display("Tests failed!"); 191 | else 192 | $display("Tests passed!"); 193 | 194 | #100; 195 | $finish(); 196 | end 197 | 198 | // Timeout check 199 | initial begin 200 | // Should not take more than the total time needed to send all characters plus 201 | // some extra spare time 202 | #((BAUD_PERIOD * 10 + INPUT_DELAY) * (NUM_CHARS) + 5000); 203 | $error("Timeout!"); 204 | $fatal(); 205 | end 206 | 207 | endmodule 208 | -------------------------------------------------------------------------------- /lab5/spec/figs/2_rv_beats.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab5/spec/figs/2_rv_beats.pdf -------------------------------------------------------------------------------- /lab5/spec/figs/2_rv_beats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab5/spec/figs/2_rv_beats.png -------------------------------------------------------------------------------- /lab5/spec/figs/backpressure.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab5/spec/figs/backpressure.pdf -------------------------------------------------------------------------------- /lab5/spec/figs/backpressure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab5/spec/figs/backpressure.png -------------------------------------------------------------------------------- /lab5/spec/figs/high_level_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab5/spec/figs/high_level_diagram.png -------------------------------------------------------------------------------- /lab5/spec/figs/pmod_a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab5/spec/figs/pmod_a.jpg -------------------------------------------------------------------------------- /lab5/spec/figs/sink_source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab5/spec/figs/sink_source.png -------------------------------------------------------------------------------- /lab5/spec/figs/uart_frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab5/spec/figs/uart_frame.png -------------------------------------------------------------------------------- /lab5/spec/figs/uart_rx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab5/spec/figs/uart_rx.png -------------------------------------------------------------------------------- /lab5/spec/figs/uart_tx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab5/spec/figs/uart_tx.png -------------------------------------------------------------------------------- /lab5/spec/spec.md: -------------------------------------------------------------------------------- 1 | # FPGA Lab 5: UART (Universal Asynchronous Receiver/Transmitter) 2 |
3 | Prof. Sophia Shao 4 |
5 |6 | TAs: Alisha Menon, Yikuan Chen, Seah Kim 7 |
8 |9 | Department of Electrical Engineering and Computer Science 10 |
11 |12 | College of Engineering, University of California, Berkeley 13 |
14 | 15 | ## Before You Begin 16 | ### Fetch Latest Lab Skeleton 17 | ```shell 18 | cd fpga_labs_sp22 19 | git pull origin master 20 | ``` 21 | 22 | ### Copy Sources From Previous Lab 23 | ```shell 24 | cd fpga_labs_sp22 25 | cp lab4/src/synchronizer.v lab5/src/. 26 | cp lab4/src/edge_detector.v lab5/src/. 27 | cp lab4/src/debouncer.v lab5/src/. 28 | ``` 29 | 30 | ### Reading 31 | - Read this document on [ready-valid interfaces](https://inst.eecs.berkeley.edu/~eecs151/fa21/files/verilog/ready_valid_interface.pdf) 32 | 33 | ## Overview 34 | In this lab we will: 35 | 36 | - Understand the ready-valid interface 37 | - Design a universal asynchronous receiver/transmitter (UART) circuit 38 | - Test the UART on the FPGA using a host computer 39 | 40 | 41 | 42 | ## Recommended Style for Writing a Finite State Machine - Two Always Blocks 43 | ```Verilog 44 | module vending_machine( 45 | input clk, reset, 46 | input