├── .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 47 | output 48 | ); 49 | //1.define state registers (state, next_state, with proper bitwidths) 50 | 51 | //2.define state names as localparams (optional but recommended to make your code clean) 52 | //e.g. 53 | localparam DEFAULT_STATE = 2'b00; 54 | 55 | //3.declare regs for output that will be produced by the combinational block 56 | //e.g. do this. Note that output_1_reg is still an combinational logic, not a sequential logic! 57 | reg output_1_int; //int for internal 58 | assign output_1 = output_1_int; 59 | 60 | //4.an always@(posedge clk) block to handle state assignment 61 | always @ (posedge clk) begin 62 | state <= next_state; // this is the only line that should be in this block. For reset, see the combinational block below 63 | end 64 | 65 | //5.an always@(*) block to handle 1) output for each state and 2) state transition logic (both of them may also depend on input) 66 | always @ (*) begin 67 | if(reset)begin 68 | next_state = DEFAULT_STATE; 69 | end else begin 70 | case(state) 71 | DEFAULT_STATE: begin 72 | output_1_int = 1'b1; 73 | if(input_1) next_state = ...; 74 | else next_state = ...; 75 | end 76 | ... 77 | endcase 78 | end 79 | end 80 | 81 | ``` 82 | 83 | ## Ready-Valid Interface 84 | Often, we want to design modules that pass data between each other but are unaware of each other's internal timing. 85 | The *ready-valid interface* is a standardized interface and protocol for timing-agnostic data movement between 2 modules. 86 | 87 | The ready-valid interface is used to send data from a *source* to a *sink*. 88 | 89 |

90 | 91 |

92 | 93 | It consists of 3 wires: 94 | - `valid` (1 bit, driven by source, received by sink) 95 | - `data` (D bits, driven by source, received by sink) 96 | - `ready` (1 bit, driven by sink, received by source) 97 | 98 | The sink uses the `ready` signal to tell the source if the sink is able to receive a new piece of data. 99 | Usually the sink can only take in a certain number of data pieces until it is full and has to process what it has already received before it can receive any more. 100 | 101 | The source uses the `valid` signal to tell the sink that the `data` bus has data it wishes to send to the sink. 102 | 103 | A ready-valid *transaction* only occurs when both `ready` and `valid` are high on a rising clock edge. 104 | If both `ready` and `valid` are high on a rising edge, the source can assume that the sink has received and *internally stored* the bits on `data`. 105 | 106 | Here are a few examples: 107 | 120 | 121 |

122 | 123 |

124 | 125 | There are two transactions that take place on the 3rd and 6th rising clock edges. 126 | Note that the source can change `data` when `valid` is not high. 127 | 128 |

129 | 130 |

131 | 139 | 140 | The sink can pull `ready` low whenever it isn't ready to accept new data. 141 | In this example, there are 2 transactions that take place on the 5th and 7th rising clock edges. 142 | When the source has `valid` high, but the sink has `ready` low we say that the sink is applying *backpressure* to the source. 143 | 144 | The data transfer from source to sink only occurs when *both* `ready` and `valid` are high on a rising edge. 145 | 146 | ## UART Serial Device 147 | In this lab, we will design a circuit that implements UART serial protocol for transmitting and receiving data over a serial interface. 148 | This will enables circuits on the FPGA to communicate with the workstation, which will allow us to programmatically send data to and from the FPGA. 149 | 150 | UART is a 2 wire protocol with one wire carrying data from the workstation → FPGA and the other one carrying data from the FPGA → workstation. 151 | Here is an overview of the setup we will use: 152 | 153 |

154 | 155 |

156 |

157 | Diagram of the entire setup 158 |

159 | 160 | The UART transmit and receive modules use a *ready-valid interface* to communicate with other modules on the FPGA. 161 | Both the UART’s receive and transmit modules will have their own separate ready-valid interface connected appropriately to other modules. 162 | 163 | Please note that the serial line itself is not a ready/valid interface. 164 | Rather, it is the modules you will work with in this lab (`uart_transmitter` and `uart_receiver`) that use the ready-valid handshake. 165 | 166 | ### UART Packet Framing 167 | On the `PYNQ-Z1` board, the physical signaling aspects (such as voltage level) of the serial connection will be taken care of by off-FPGA devices. 168 | From the FPGA's perspective, there are two signals, `FPGA_SERIAL_RX` and `FPGA_SERIAL_TX`, which correspond to the receive-side and transmit-side pins of the serial port. 169 | The FPGA's job is to correctly frame 8-bit data words going back and forth across the serial connection. 170 | The figure below shows how a single 8-bit data word is transferred over the serial line using the UART protocol. 171 | 172 |

173 | 174 |

175 |

176 | Framing of a UART packet 177 |

178 | 179 | In the idle state the serial line is held high. 180 | When the TX side is ready to send a 8-bit word, it pulls the line low. 181 | This is called the start bit. 182 | Because UART is an asynchronous protocol, all timing within the frame is relative to when the start bit is first sent (or detected, on the receive side). 183 | 184 | The frame is divided up in to 10 uniformly sized bits: the start bit, 8 data bits, and then the stop bit. 185 | The width of a bit in cycles of the system clock is given by the system clock frequency (`125 MHz`) divided by the baudrate. 186 | The baudrate is the number of bits sent per second; in this lab the baudrate will be **115200**. 187 | Notice that both sides must agree on a baudrate for this scheme to be feasible. 188 | 189 | ### UART Receiver 190 |

191 | 192 |

193 |

194 | Connectivity of the UART receiver 195 |

196 | 197 | The receive side of the UART is just a shift register that shifts bits in from the serial line. 198 | However, care must be taken into determining *when* to shift bits in. 199 | If we attempt to sample the `FPGA_SERIAL_RX` signal directly on the edge between two symbols, we are likely to sample on the wrong side of the edge and get the wrong value for that bit. 200 | One solution is to wait halfway into a cycle (until `SampleTime` on the diagram) before reading a bit in to the shift register. 201 | 202 | The UART receiver module sends the received 8-bit word to a consumer block on the FPGA via a ready-valid interface. 203 | Once we have received a full UART packet over the serial port, the `valid` signal should go high until the `ready` signal goes high, after which the `valid` signal will be driven low until we receive another UART packet. 204 | 205 | You do not need to implement the UART receiver as it is provided to you in `lab5/src/uart_receiver.v`, but you should refer to its implementation when writing the `uart_transmitter`. 206 | 207 | ### UART Transmitter 208 |

209 | 210 |

211 |

212 | Connectivity of the UART transmitter 213 |

214 | 215 | The UART Transmitter receives a 8-bit word from a producer block on FPGA via the ready-valid interface. 216 | Once we have a 8-bit word that we want to send (i.e., once `valid` is high, and the transmitter is `ready`), transmitting it involves shifting each bit of the `data[7:0]` bus, plus the start and stop bits, out of a shift register on to the serial line. 217 | 218 | Remember, the serial baudrate is much slower than the system clock, so we must wait `SymbolEdgeTime = ClockFreq / BaudRate` cycles between changing the bit we're putting on the serial line. 219 | After we have shifted all 10 bits out of the shift register, we are done unless we have to send another frame immediately after. 220 | The transmitter should not be `ready` when it is in a middle of sending a frame. 221 | 222 | **Your task** is to complete the implementation of UART transmitter in `lab5/src/uart_transmitter.v`. 223 | 224 | ### UART Transmitter Verification 225 | We have provided 2 testbenches to check the UART transmitter. 226 | - `sim/uart_transmitter_tb.v` 227 | - `sim/uart2uart_tb.v` 228 | 229 | You can run them as usual; they will print out any errors during execution. 230 | 231 | ## UART Echo Setup 232 | Look at the state machine implemented for you in `src/z1top.v`. 233 | It pulls characters from the on-chip UART receiver, inverts its case (e.g. `a` → `A`), and sends it to the on-chip UART transmitter, which sends the character to the host computer. 234 | 235 | We have provided 2 testbenches to verify this setup. 236 | Both instantiate `z1top` directly, making them *top-level* testbenches. 237 | - `sim/simple_echo_tb.v` 238 | - `sim/echo_tb.v` 239 | 240 | As the names imply, the `simple_echo_tb` is simpler, and only tests the echoing of a single character, while the `echo_tb` tests multiple character echoes in a row. 241 | 242 | Once you have successfully run all the testbenches, and manually examined the waveforms to check for correctness, you can move on. 243 | 244 | ## On the FPGA 245 | Use the standard `make impl` and `make program` to create and program a bitstream. 246 | 247 | **Pay attention to the warnings** generated by Vivado in `build/synth/synth.log`. 248 | It's possible to write your Verilog in such a way that it passes behavioural simulation but doesn't work in implementation. 249 | Warnings about `multi driven nets`, for example, can lead to certain logic pathways being optimized out. 250 | 251 | ### PMOD USB-UART 252 | The PYNQ-Z1 does not have an RS-232 serial interface connected to the FPGA fabric. 253 | So we'll be using the [PMOD USB-UART](https://store.digilentinc.com/pmod-usbuart-usb-to-uart-interface/) extension module to add a UART interface to the Pynq board. 254 | Connect the PMOD module to the **top** row of the PMOD A port on the Pynq, and connect a USB cable from the USB-UART PMOD to your computer (this is already done in the Cory 111 workstations). 255 | 256 | *Note:* Make sure that the power selection jumper on the PMOD USB-UART is set to LCL3V3. 257 | 258 |

259 | 260 |

261 |

262 | PMOD USB-UART plugged in with correct power jumper setting (blue). 263 |

264 | 265 | ### Hello World 266 | Reset the UART circuit on your FPGA with `buttons[0]`. 267 | 268 | On your workstation, run: 269 | ```shell 270 | screen $SERIALTTY 115200 271 | ``` 272 | 273 | This opens `screen`, a terminal emulator, and connected to the serial device with a baud rate of 115200. 274 | When you type a character into the terminal, it is sent to the FPGA over the `FPGA_SERIAL_RX` line, encoded in ASCII. 275 | The state machine in `z1top` may modify the character you sent it and will then push a new character over the `FPGA_SERIAL_TX` line to your workstation. 276 | When `screen` receives a character, it will display it in the terminal. 277 | 278 | If you have a working design, you can **type a few characters into the terminal** and have them echoed to you (with inverted case if you type letters). 279 | Make sure that if you type really fast that all characters still display properly. 280 | 281 | If you see some weird garbage symbols then the data is getting corrupted and something is likely wrong. 282 | If you see this happening very infrequently, don't just hope that it won't happen while the TA is doing the checkoff; take the time now to figure out what is wrong. 283 | UART bugs are a common source of headaches for groups during the first project checkpoint. 284 | 285 | To close `screen`, type `Ctrl-a` then `Shift-k` and answer `y` to the confirmation prompt. 286 | If you don't close `screen` properly, other students won't be able to access the serial port on your workstation. 287 | 288 | If you try opening `screen` and it terminates after a few seconds with an error saying `Sorry, can't find a PTY` or `Device is busy`, execute the command `killscreen` which will kill all open screen sessions that other students may have left open. 289 | Then run `screen` again. 290 | 291 | Use `screen -r` to re-attach to a non-terminated screen session. 292 | You can also reboot the computer to clear all active `screen` sessions. 293 | 294 | 295 | ## Lab Deliverables 296 | ### Lab Checkoff (due in two weeks from your lab section) 297 | To checkoff for this lab, have these things ready to show the TA: 298 | - Go through the UART simulation results and show that your UART behaves as expected. What do the testbenches do? 299 | - Demonstrate that you can type characters rapidly on the keyboard and have them echoed back in your `screen` session 300 | 301 | ## Personal Laptop Instructions 302 | 303 | ### Linux/OSX 304 | After plugging in the USB cable, run `dmesg` and observe the output: 305 | ```text 306 | [7444636.941491] ftdi_sio 1-2:1.0: FTDI USB Serial Device converter detected 307 | [7444636.941621] usb 1-2: Detected FT232RL 308 | [7444636.942062] usb 1-2: FTDI USB Serial Device converter now attached to ttyUSB0 309 | ``` 310 | 311 | Then connect using `sudo screen /dev/ttyUSB0 115200` 312 | 313 | ### Windows 314 | After plugging in the USB cable, you may be prompted to install the FTDI drivers, so do that. 315 | Follow the [steps from here](https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842446/Setup+a+Serial+Console) to use PuTTY to connect to the UART. 316 | 317 | ## Acknowledgement 318 | This lab is the result of the work of many EECS151/251 GSIs over the years including: 319 | - Sp12: James Parker, Daiwei Li, Shaoyi Cheng 320 | - Sp13: Shaoyi Cheng, Vincent Lee 321 | - Fa14: Simon Scott, Ian Juch 322 | - Fa15: James Martin 323 | - Fa16: Vighnesh Iyer 324 | - Fa17: George Alexandrov, Vighnesh Iyer, Nathan Narevsky 325 | - Sp18: Arya Reais-Parsi, Taehwan Kim 326 | - Fa18: Ali Moin, George Alexandrov, Andy Zhou 327 | - Sp19: Christopher Yarp, Arya Reais-Parsi 328 | - Fa19: Vighnesh Iyer, Rebekah Zhao, Ryan Kaveh 329 | - Sp20: Tan Nguyen 330 | - Fa20: Charles Hong, Kareem Ahmad, Zhenghan Lin 331 | - Sp21: Sean Huang, Tan Nguyen 332 | - Fa21: Vighnesh Iyer, Charles Hong, Zhenghan Lin, Alisha Menon 333 | - Sp22: Alisha Menon, Yikuan Chen, Seah Kim 334 | -------------------------------------------------------------------------------- /lab5/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 | -------------------------------------------------------------------------------- /lab5/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 | -------------------------------------------------------------------------------- /lab5/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 | -------------------------------------------------------------------------------- /lab5/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 | -------------------------------------------------------------------------------- /lab5/src/uart.v: -------------------------------------------------------------------------------- 1 | module uart #( 2 | parameter CLOCK_FREQ = 125_000_000, 3 | parameter BAUD_RATE = 115_200 4 | ) ( 5 | input clk, 6 | input reset, 7 | 8 | input [7:0] data_in, 9 | input data_in_valid, 10 | output data_in_ready, 11 | 12 | output [7:0] data_out, 13 | output data_out_valid, 14 | input data_out_ready, 15 | 16 | input serial_in, 17 | output serial_out 18 | ); 19 | reg serial_in_reg, serial_out_reg; 20 | wire serial_out_tx; 21 | assign serial_out = serial_out_reg; 22 | always @ (posedge clk) begin 23 | serial_out_reg <= reset ? 1'b1 : serial_out_tx; 24 | serial_in_reg <= reset ? 1'b1 : serial_in; 25 | end 26 | 27 | uart_transmitter #( 28 | .CLOCK_FREQ(CLOCK_FREQ), 29 | .BAUD_RATE(BAUD_RATE) 30 | ) uatransmit ( 31 | .clk(clk), 32 | .reset(reset), 33 | .data_in(data_in), 34 | .data_in_valid(data_in_valid), 35 | .data_in_ready(data_in_ready), 36 | .serial_out(serial_out_tx) 37 | ); 38 | 39 | uart_receiver #( 40 | .CLOCK_FREQ(CLOCK_FREQ), 41 | .BAUD_RATE(BAUD_RATE) 42 | ) uareceive ( 43 | .clk(clk), 44 | .reset(reset), 45 | .data_out(data_out), 46 | .data_out_valid(data_out_valid), 47 | .data_out_ready(data_out_ready), 48 | .serial_in(serial_in_reg) 49 | ); 50 | endmodule 51 | -------------------------------------------------------------------------------- /lab5/src/uart_receiver.v: -------------------------------------------------------------------------------- 1 | module uart_receiver #( 2 | parameter CLOCK_FREQ = 125_000_000, 3 | parameter BAUD_RATE = 115_200) 4 | ( 5 | input clk, 6 | input reset, 7 | 8 | output [7:0] data_out, 9 | output data_out_valid, 10 | input data_out_ready, 11 | 12 | input serial_in 13 | ); 14 | // See diagram in the lab guide 15 | localparam SYMBOL_EDGE_TIME = CLOCK_FREQ / BAUD_RATE; 16 | localparam SAMPLE_TIME = SYMBOL_EDGE_TIME / 2; 17 | localparam CLOCK_COUNTER_WIDTH= $clog2(SYMBOL_EDGE_TIME); 18 | 19 | wire symbol_edge; 20 | wire sample; 21 | wire start; 22 | wire rx_running; 23 | 24 | reg [9:0] rx_shift; 25 | reg [3:0] bit_counter; 26 | reg [CLOCK_COUNTER_WIDTH-1:0] clock_counter; 27 | reg has_byte; 28 | 29 | //--|Signal Assignments|------------------------------------------------------ 30 | 31 | // Goes high at every symbol edge 32 | /* verilator lint_off WIDTH */ 33 | assign symbol_edge = clock_counter == (SYMBOL_EDGE_TIME - 1); 34 | /* lint_on */ 35 | 36 | // Goes high halfway through each symbol 37 | /* verilator lint_off WIDTH */ 38 | assign sample = clock_counter == SAMPLE_TIME; 39 | /* lint_on */ 40 | 41 | // Goes high when it is time to start receiving a new character 42 | assign start = !serial_in && !rx_running; 43 | 44 | // Goes high while we are receiving a character 45 | assign rx_running = bit_counter != 4'd0; 46 | 47 | // Outputs 48 | assign data_out = rx_shift[8:1]; 49 | assign data_out_valid = has_byte && !rx_running; 50 | 51 | //--|Counters|---------------------------------------------------------------- 52 | 53 | // Counts cycles until a single symbol is done 54 | always @ (posedge clk) begin 55 | clock_counter <= (start || reset || symbol_edge) ? 0 : clock_counter + 1; 56 | end 57 | 58 | // Counts down from 10 bits for every character 59 | always @ (posedge clk) begin 60 | if (reset) begin 61 | bit_counter <= 0; 62 | end else if (start) begin 63 | bit_counter <= 10; 64 | end else if (symbol_edge && rx_running) begin 65 | bit_counter <= bit_counter - 1; 66 | end 67 | end 68 | 69 | //--|Shift Register|---------------------------------------------------------- 70 | always @(posedge clk) begin 71 | if (sample && rx_running) rx_shift <= {serial_in, rx_shift[9:1]}; 72 | end 73 | 74 | //--|Extra State For Ready/Valid|--------------------------------------------- 75 | // This block and the has_byte signal aren't needed in the uart_transmitter 76 | always @ (posedge clk) begin 77 | if (reset) has_byte <= 1'b0; 78 | else if (bit_counter == 1 && symbol_edge) has_byte <= 1'b1; 79 | else if (data_out_ready) has_byte <= 1'b0; 80 | end 81 | endmodule 82 | -------------------------------------------------------------------------------- /lab5/src/uart_transmitter.v: -------------------------------------------------------------------------------- 1 | module uart_transmitter #( 2 | parameter CLOCK_FREQ = 125_000_000, 3 | parameter BAUD_RATE = 115_200) 4 | ( 5 | input clk, 6 | input reset, 7 | 8 | input [7:0] data_in, 9 | input data_in_valid, 10 | output data_in_ready, 11 | 12 | output serial_out 13 | ); 14 | // See diagram in the lab guide 15 | localparam SYMBOL_EDGE_TIME = CLOCK_FREQ / BAUD_RATE; 16 | localparam CLOCK_COUNTER_WIDTH = $clog2(SYMBOL_EDGE_TIME); 17 | 18 | // Remove these assignments when implementing this module 19 | assign serial_out = 1'b0; 20 | assign data_in_ready = 1'b0; 21 | endmodule 22 | -------------------------------------------------------------------------------- /lab5/src/z1top.v: -------------------------------------------------------------------------------- 1 | module z1top #( 2 | parameter CLOCK_FREQ = 125_000_000, 3 | parameter BAUD_RATE = 115_200, 4 | /* verilator lint_off REALCVT */ 5 | // Sample the button signal every 500us 6 | parameter integer B_SAMPLE_CNT_MAX = 0.0005 * CLOCK_FREQ, 7 | // The button is considered 'pressed' after 100ms of continuous pressing 8 | parameter integer B_PULSE_CNT_MAX = 0.100 / 0.0005 9 | /* lint_on */ 10 | )( 11 | input CLK_125MHZ_FPGA, 12 | input [3:0] BUTTONS, 13 | input [1:0] SWITCHES, 14 | output [5:0] LEDS, 15 | output AUD_PWM, 16 | output AUD_SD, 17 | input FPGA_SERIAL_RX, 18 | output FPGA_SERIAL_TX 19 | ); 20 | wire [3:0] buttons_pressed; 21 | button_parser #( 22 | .WIDTH(4), 23 | .SAMPLE_CNT_MAX(B_SAMPLE_CNT_MAX), 24 | .PULSE_CNT_MAX(B_PULSE_CNT_MAX) 25 | ) bp ( 26 | .clk(CLK_125MHZ_FPGA), 27 | .in(BUTTONS), 28 | .out(buttons_pressed) 29 | ); 30 | assign AUD_PWM = 1'b0; 31 | assign AUD_SD = 1'b0; 32 | 33 | wire rst; 34 | assign rst = buttons_pressed[0]; 35 | 36 | reg [7:0] data_in; 37 | wire [7:0] data_out; 38 | wire data_in_valid, data_in_ready, data_out_valid, data_out_ready; 39 | 40 | // This UART is on the FPGA and communicates with your desktop 41 | // using the FPGA_SERIAL_TX, and FPGA_SERIAL_RX signals. The ready/valid 42 | // interface for this UART is used on the FPGA design. 43 | uart # ( 44 | .CLOCK_FREQ(CLOCK_FREQ), 45 | .BAUD_RATE(BAUD_RATE) 46 | ) on_chip_uart ( 47 | .clk(CLK_125MHZ_FPGA), 48 | .reset(rst), 49 | .data_in(data_in), 50 | .data_in_valid(data_in_valid), 51 | .data_in_ready(data_in_ready), 52 | .data_out(data_out), 53 | .data_out_valid(data_out_valid), 54 | .data_out_ready(data_out_ready), 55 | .serial_in(FPGA_SERIAL_RX), 56 | .serial_out(FPGA_SERIAL_TX) 57 | ); 58 | 59 | // This is a small state machine that will pull a character from the uart_receiver 60 | // over the ready/valid interface, modify that character, and send the character 61 | // to the uart_transmitter, which will send it over the serial line. 62 | 63 | // If a ASCII letter is received, its case will be reversed and sent back. Any other 64 | // ASCII characters will be echoed back without any modification. 65 | reg has_char; 66 | reg [7:0] char; 67 | 68 | always @(posedge CLK_125MHZ_FPGA) begin 69 | if (rst) has_char <= 1'b0; 70 | else has_char <= has_char ? !data_in_ready : data_out_valid; 71 | end 72 | 73 | always @(posedge CLK_125MHZ_FPGA) begin 74 | if (!has_char) char <= data_out; 75 | end 76 | 77 | always @ (*) begin 78 | if (char >= 8'd65 && char <= 8'd90) data_in = char + 8'd32; 79 | else if (char >= 8'd97 && char <= 8'd122) data_in = char - 8'd32; 80 | else data_in = char; 81 | end 82 | 83 | assign data_in_valid = has_char; 84 | assign data_out_ready = !has_char; 85 | endmodule 86 | -------------------------------------------------------------------------------- /lab5/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 | 37 | ##Pmod Header JA 38 | #set_property -dict { PACKAGE_PIN Y18 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_L17P_T2_34 Sch=ja_p[1] 39 | set_property -dict { PACKAGE_PIN Y19 IOSTANDARD LVCMOS33 } [get_ports { FPGA_SERIAL_TX }]; #IO_L17N_T2_34 Sch=ja_n[1] 40 | set_property -dict { PACKAGE_PIN Y16 IOSTANDARD LVCMOS33 } [get_ports { FPGA_SERIAL_RX }]; #IO_L7P_T1_34 Sch=ja_p[2] 41 | #set_property -dict { PACKAGE_PIN Y17 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L7N_T1_34 Sch=ja_n[2] 42 | #set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L12P_T1_MRCC_34 Sch=ja_p[3] 43 | #set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L12N_T1_MRCC_34 Sch=ja_n[3] 44 | #set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22P_T3_34 Sch=ja_p[4] 45 | #set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22N_T3_34 Sch=ja_n[4] 46 | -------------------------------------------------------------------------------- /lab6/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefrag 2 | -------------------------------------------------------------------------------- /lab6/sim/fifo_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | `define CLK_PERIOD 8 4 | 5 | module fifo_tb(); 6 | localparam WIDTH = 32; 7 | localparam LOGDEPTH = 3; 8 | localparam DEPTH = (1 << LOGDEPTH); 9 | 10 | reg clk = 0; 11 | reg rst = 0; 12 | 13 | always #(`CLK_PERIOD/2) clk <= ~clk; 14 | 15 | // Reg filled with test vectors for the testbench 16 | reg [WIDTH-1:0] test_values[50-1:0]; 17 | // Reg used to collect the data read from the FIFO 18 | reg [WIDTH-1:0] received_values[50-1:0]; 19 | 20 | // Enqueue signals (Write to FIFO) 21 | reg wr_en; 22 | reg [WIDTH-1:0] din; 23 | wire full; 24 | 25 | // Dequeue signals (Read from FIFO) 26 | wire empty; 27 | wire [WIDTH-1:0] dout; 28 | reg rd_en; 29 | 30 | fifo #( 31 | .WIDTH(WIDTH), 32 | .DEPTH(DEPTH) 33 | ) dut ( 34 | .clk(clk), 35 | .rst(rst), 36 | 37 | .wr_en(wr_en), // input 38 | .din(din), // input 39 | .full(full), // output 40 | 41 | .empty(empty), // output 42 | .dout(dout), // output 43 | .rd_en(rd_en) // input 44 | ); 45 | 46 | // This could be a bit verbose 47 | /* 48 | always @(posedge clk) begin 49 | $display("At time %d, enq_valid=%d, enq_ready=%d, enq_data=%d, deq_valid=%d, deq_ready=%d, deq_data=%d, WRITE=%d, READ=%d", 50 | $time, 51 | enq_valid, enq_ready, enq_data, 52 | deq_valid, deq_ready, deq_data, 53 | (enq_valid && enq_ready ? enq_data : 32'dX), 54 | (deq_valid && deq_ready ? deq_data : 32'dX)); 55 | end 56 | */ 57 | 58 | // This task will push some data to the FIFO through the write interface 59 | // If violate_interface == 1'b1, we will force 'wr_en' high even if the FIFO indicates it is full 60 | // If violate_interface == 1'b0, we won't write if the FIFO indicates it is full 61 | task write_to_fifo; 62 | input [WIDTH-1:0] write_data; 63 | input violate_interface; 64 | begin 65 | #1; 66 | // If we want to not violate the interface agreement, if we are already full, don't write 67 | if (!violate_interface && full) begin 68 | wr_en = 1'b0; 69 | end 70 | // In all other cases, we will force a write 71 | else begin 72 | wr_en = 1'b1; 73 | end 74 | 75 | // Write should be performed when enq_ready and enq_valid are HIGH 76 | din = write_data; 77 | 78 | // Wait for the clock edge to perform the write 79 | @(posedge clk); #1; 80 | 81 | // Deassert write 82 | wr_en = 1'b0; 83 | end 84 | endtask 85 | 86 | // This task will read some data from the FIFO through the read interface 87 | // violate_interface does the same as for the write_to_fifo task 88 | task read_from_fifo; 89 | input violate_interface; 90 | output [WIDTH-1:0] read_data; 91 | begin 92 | #1; 93 | if (!violate_interface && empty) begin 94 | rd_en = 1'b0; 95 | end 96 | else begin 97 | rd_en = 1'b1; 98 | end 99 | 100 | // Deassert read 101 | @(posedge clk); #1; 102 | 103 | read_data = dout; 104 | rd_en = 1'b0; 105 | end 106 | endtask 107 | 108 | integer i; 109 | integer num_mismatches; 110 | integer num_items = 50; 111 | integer write_delay, read_delay; 112 | 113 | /* Signals used for the simultaneous read/write test */ 114 | integer write_idx = 0; 115 | integer write_start = 0; 116 | integer read_idx = 0; 117 | integer read_start = 0; 118 | 119 | integer z; 120 | initial begin: TB 121 | `ifndef IVERILOG 122 | $vcdpluson; 123 | $vcdplusmemon; 124 | `endif 125 | `ifdef IVERILOG 126 | $dumpfile("fifo_tb.fst"); 127 | $dumpvars(0, fifo_tb); 128 | for(z = 0; z < DEPTH; z = z + 1) begin 129 | // TODO: replace this line with a path to the 2D reg in your FIFO 130 | // to show each entry in the waveform 131 | // $dumpvars(0, dut.memory[z]); 132 | end 133 | `endif 134 | 135 | $display("This testbench was run with these params:"); 136 | $display("CLK_PERIOD = %d, WIDTH = %d, DEPTH = %d", `CLK_PERIOD, WIDTH, DEPTH); 137 | 138 | // Generate data to write to the FIFO 139 | for (i = 0; i < 50; i = i + 1) begin 140 | test_values[i] <= i + 1000; 141 | end 142 | 143 | wr_en = 0; 144 | din = 0; 145 | rd_en = 0; 146 | 147 | rst = 1'b1; 148 | @(posedge clk); #1; 149 | rst = 1'b0; 150 | @(posedge clk); #1; 151 | 152 | // ==================== Basic tests =================================== 153 | // Let's begin with a simple complete write and read sequence to the FIFO 154 | 155 | // Check initial conditions, verify that the FIFO is not full, it is empty 156 | if (empty !== 1'b1) begin 157 | $error("Failure: After reset, the FIFO isn't empty. empty = %b", empty); 158 | end 159 | 160 | if (full !== 1'b0) begin 161 | $error("Failure: After reset, the FIFO is full. full = %b", full); 162 | end 163 | 164 | @(posedge clk); 165 | 166 | // Begin pushing data into the FIFO with a 1 cycle delay in between each write operation 167 | for (i = 0; i < DEPTH - 1; i = i + 1) begin 168 | write_to_fifo(test_values[i], 1'b0); 169 | 170 | // Perform checks on empty, full 171 | if (empty === 1'b1) begin 172 | $error("Failure: While being filled, FIFO said it was empty"); 173 | end 174 | 175 | if (full === 1'b1) begin 176 | $error("Failure: While being filled, FIFO was full before all entries were written"); 177 | end 178 | 179 | // Insert single-cycle delay between each write 180 | @(posedge clk); 181 | end 182 | 183 | // Perform the final write 184 | write_to_fifo(test_values[DEPTH-1], 1'b0); 185 | 186 | // Check that the FIFO is now full 187 | if (full !== 1'b1 || empty === 1'b1) begin 188 | $error("Failure: FIFO wasn't full or empty went high after writing all values. full = %b, empty = %b", full, empty); 189 | end 190 | 191 | // Cycle the clock, the FIFO should still be full! 192 | repeat (10) @(posedge clk); 193 | // The FIFO should still be full! 194 | if (full !== 1'b1 || empty === 1'b1) begin 195 | $error("Failure: Cycling the clock while the FIFO is full shouldn't change its state! full = %b, empty = %b", full, empty); 196 | end 197 | 198 | // Try stuffing the FIFO with more data while it's full (overflow protection check) 199 | repeat (20) begin 200 | write_to_fifo(0, 1'b1); 201 | // Check that the FIFO is still full, has the max num of entries, and isn't empty 202 | if (full !== 1'b1 || empty === 1'b1) begin 203 | $error("Failure: Overflowing the FIFO changed its state (your FIFO should have overflow protection) full = %b, empty = %b", full, empty); 204 | end 205 | end 206 | 207 | repeat (5) @(posedge clk); 208 | 209 | // Read from the FIFO one by one with a 1 cycle delay in between reads 210 | for (i = 0; i < DEPTH - 1; i = i + 1) begin 211 | read_from_fifo(1'b0, received_values[i]); 212 | 213 | // Perform checks on empty, full 214 | if (empty === 1'b1) begin 215 | $error("Failure: FIFO was empty as its being drained"); 216 | end 217 | if (full === 1'b1) begin 218 | $error("Failure: FIFO was full as its being drained"); 219 | end 220 | 221 | @(posedge clk); 222 | end 223 | 224 | // Perform the final read 225 | read_from_fifo(1'b0, received_values[DEPTH-1]); 226 | // Check that the FIFO is now empty 227 | if (full !== 1'b0 || empty !== 1'b1) begin 228 | $error("Failure: FIFO wasn't empty or full is high after the FIFO has been drained. full = %b, empty = %b", full, empty); 229 | end 230 | 231 | // Cycle the clock and perform the same checks 232 | repeat (10) @(posedge clk); 233 | if (full !== 1'b0 || empty !== 1'b1) begin 234 | $error("Failure: FIFO should be empty after it has been drained. full = %b, empty = %b", full, empty); 235 | end 236 | 237 | // Finally, let's check that the data we received from the FIFO equals the data that we wrote to it 238 | num_mismatches = 0; 239 | for (i = 0; i < DEPTH; i = i + 1) begin 240 | if (test_values[i] !== received_values[i]) begin 241 | $error("Failure: Data received from FIFO not equal to data written. Entry %d, got %d, expected %d", i, received_values[i], test_values[i]); 242 | num_mismatches = num_mismatches + 1; 243 | end 244 | end 245 | 246 | // Now attempt a read underflow 247 | repeat (10) read_from_fifo(1'b1, received_values[0]); 248 | // Nothing should change, perform the same checks on full and empty 249 | if (full !== 1'b0 || empty !== 1'b1) begin 250 | $error("Failure: Empty FIFO wasn't empty or full went high when trying to read. full = %b, empty = %b", full, empty); 251 | end 252 | 253 | repeat (10) @(posedge clk); 254 | if (num_mismatches > 0) 255 | $fatal(); 256 | 257 | $display("All the basic tests passed!"); 258 | 259 | // ==================== Harder tests ================================== 260 | // Begin pushing data into the FIFO in successive cycles 261 | for (i = 0; i < DEPTH; i = i + 1) begin 262 | write_to_fifo(test_values[i], 1'b0); 263 | end 264 | 265 | // Add some delay 266 | repeat (5) @(posedge clk); 267 | 268 | // Read from the FIFO in successive cycles 269 | for (i = 0; i < DEPTH; i = i + 1) begin 270 | read_from_fifo(1'b0, received_values[i]); 271 | end 272 | 273 | num_mismatches = 0; 274 | for (i = 0; i < DEPTH; i = i + 1) begin 275 | if (test_values[i] !== received_values[i]) begin 276 | $error("Failure: Data received from FIFO not equal to data written. Entry %d, got %d, expected %d", i, received_values[i], test_values[i]); 277 | num_mismatches = num_mismatches + 1; 278 | end 279 | end 280 | if (num_mismatches > 0) 281 | $fatal(); 282 | 283 | repeat (10) @(posedge clk); 284 | assert(empty == 1'b1); 285 | 286 | // Write and Read from FIFO for some number of items concurrently 287 | // Test with different combinations of the following variables 288 | num_items = 50; // number of items to be sent and received 289 | write_delay = 0; // number of cycles to the next write 290 | read_delay = 0; // number of cycles to the next read 291 | fork 292 | begin 293 | write_start = 1; 294 | write_idx = 0; 295 | for (i = 0; i < num_items; i = i + 1) begin 296 | write_to_fifo(test_values[write_idx], 1'b0); 297 | repeat (write_delay) @(posedge clk); 298 | write_idx = write_idx + 1; 299 | end 300 | write_start = 0; 301 | end 302 | begin 303 | repeat((write_delay + 2)) @(posedge clk); 304 | read_start = 1; 305 | read_idx = 0; 306 | while (!empty) begin 307 | read_from_fifo(1'b0, received_values[read_idx]); 308 | repeat (read_delay) @(posedge clk); 309 | read_idx = read_idx + 1; 310 | end 311 | read_start = 0; 312 | end 313 | join 314 | 315 | repeat (10) @(posedge clk); 316 | 317 | num_mismatches = 0; 318 | for (i = 0; i < num_items; i = i + 1) begin 319 | if (test_values[i] !== received_values[i]) begin 320 | $error("Failure: Data received from FIFO not equal to data written. Entry %d, got %d, expected %d", i, received_values[i], test_values[i]); 321 | num_mismatches = num_mismatches + 1; 322 | end 323 | end 324 | if (num_mismatches > 0) 325 | $fatal(); 326 | 327 | $display("All the hard tests passed!"); 328 | $finish(); 329 | end 330 | 331 | endmodule 332 | -------------------------------------------------------------------------------- /lab6/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 | -------------------------------------------------------------------------------- /lab6/sim/system_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/100ps 2 | 3 | `define SECOND 1000000000 4 | `define MS 1000000 5 | `define CLK_PERIOD 8 6 | `define B_SAMPLE_CNT_MAX 5 7 | `define B_PULSE_CNT_MAX 5 8 | 9 | `define CLOCK_FREQ 125_000_000 10 | `define BAUD_RATE 115_200 11 | // Number of cycles to send one character using the UART 12 | `define CYCLES_PER_CHAR ((`CLOCK_FREQ / `BAUD_RATE) * 10) 13 | // Make this a little longer than the time to send a character over UART so 14 | // the FIFO will buffer UART characters 15 | `define CYCLES_PER_SECOND (`CYCLES_PER_CHAR * 6) 16 | 17 | module system_tb(); 18 | reg clk = 0; 19 | wire audio_pwm; 20 | wire [5:0] leds; 21 | reg [2:0] buttons; 22 | reg [1:0] switches; 23 | reg rst; 24 | reg [7:0] data_in; 25 | reg data_in_valid; 26 | wire data_in_ready; 27 | 28 | wire FPGA_SERIAL_RX, FPGA_SERIAL_TX; 29 | 30 | // Generate system clock 31 | always #(`CLK_PERIOD/2) clk <= ~clk; 32 | 33 | z1top #( 34 | .B_SAMPLE_CNT_MAX(`B_SAMPLE_CNT_MAX), 35 | .B_PULSE_CNT_MAX(`B_PULSE_CNT_MAX), 36 | .CLOCK_FREQ(`CLOCK_FREQ), 37 | .BAUD_RATE(`BAUD_RATE), 38 | .CYCLES_PER_SECOND(`CYCLES_PER_SECOND) 39 | ) top ( 40 | .CLK_125MHZ_FPGA(clk), 41 | .BUTTONS({buttons, rst}), 42 | .SWITCHES(switches), 43 | .LEDS(leds), 44 | .AUD_PWM(audio_pwm), 45 | .FPGA_SERIAL_RX(FPGA_SERIAL_RX), 46 | .FPGA_SERIAL_TX(FPGA_SERIAL_TX) 47 | ); 48 | 49 | // Instantiate an off-chip UART here that uses the RX and TX lines 50 | // You can refer to the echo_testbench from lab 4 51 | uart #( 52 | .BAUD_RATE(`BAUD_RATE), 53 | .CLOCK_FREQ(`CLOCK_FREQ) 54 | ) off_chip_uart ( 55 | .clk(clk), 56 | .reset(rst), 57 | .data_in(data_in), 58 | .data_in_valid(data_in_valid), 59 | .data_in_ready(data_in_ready), 60 | .data_out(), 61 | .data_out_valid(), 62 | .data_out_ready(1'b0), 63 | .serial_in(FPGA_SERIAL_TX), 64 | .serial_out(FPGA_SERIAL_RX) 65 | ); 66 | 67 | task ua_send; 68 | input [7:0] data; 69 | begin 70 | while (!data_in_ready) begin 71 | @(posedge clk); 72 | end 73 | #1; 74 | data_in_valid = 'b1; 75 | data_in = data; 76 | @(posedge clk); #1; 77 | data_in_valid = 'b0; 78 | end 79 | endtask 80 | 81 | initial begin 82 | `ifndef IVERILOG 83 | $vcdpluson; 84 | `endif 85 | `ifdef IVERILOG 86 | $dumpfile("system_tb.fst"); 87 | $dumpvars(0, system_tb); 88 | `endif 89 | data_in = 8'd0; 90 | data_in_valid = 1'b0; 91 | buttons = 0; 92 | switches = 0; 93 | // Simulate pushing the reset button and holding it for a while 94 | rst = 1'b0; 95 | repeat (5) @(posedge clk); #1; 96 | rst = 1'b1; 97 | repeat (40) @(posedge clk); #1; 98 | rst = 1'b0; 99 | 100 | // Send characters through the off_chip_uart 101 | fork 102 | // Host -> FPGA sending thread 103 | begin 104 | ua_send("z"); 105 | ua_send("x"); 106 | ua_send("c"); 107 | end 108 | // FPGA checking thread 109 | begin 110 | // Initially the fcw should be 0 111 | // assert(top.nco.fcw == 0); 112 | 113 | // It takes `CYCLES_PER_CHAR cycles for the UART to send the 114 | // FPGA one character 115 | repeat (`CYCLES_PER_CHAR) @(posedge clk); 116 | 117 | // Wait a few more cycles for the piano to fetch the character 118 | // from the RX FIFO 119 | repeat (10) @(posedge clk); 120 | 121 | // Check the FCW is what you expect 122 | // assert(top.nco.fcw == WHAT YOU EXPECT) 123 | 124 | // Wait for the next note to begin playing 125 | // recall note_length = 1/5th of a second by default 126 | repeat (`CYCLES_PER_SECOND / 5 + 10) @(posedge clk); 127 | 128 | // Check the FCW is what you expect 129 | // assert(top.nco.fcw == WHAT YOU EXPECT) 130 | 131 | // TODO: add more stimulus and assertions, adjust note_length 132 | end 133 | join 134 | `ifndef IVERILOG 135 | $vcdplusoff; 136 | `endif 137 | $finish(); 138 | end 139 | 140 | initial begin 141 | repeat (`CYCLES_PER_CHAR + `CYCLES_PER_SECOND * 4) @(posedge clk); 142 | $error("Timing out"); 143 | $fatal(); 144 | end 145 | endmodule 146 | -------------------------------------------------------------------------------- /lab6/spec/figs/Lab6_Block_Diagram.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab6/spec/figs/Lab6_Block_Diagram.pdf -------------------------------------------------------------------------------- /lab6/spec/figs/Lab6_Block_Diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab6/spec/figs/Lab6_Block_Diagram.png -------------------------------------------------------------------------------- /lab6/spec/figs/Lab6_Block_Diagram.xml: -------------------------------------------------------------------------------- 1 | 7V1bc6O4Ev41rjrnwS5u4vJoJ5k9u5U5k0qytTv74sIg28wQ8GCcxPvrV1xk0AUs2wLHs87DTBBCCHV/X7daLWWg37y8/5K4q+Xn2IfhQFP894F+O9A0xwHo36xgWxQA0ykKFkngF0VqVfAU/A3LQqUs3QQ+XBMV0zgO02BFFnpxFEEvJcrcJInfyGrzOCTfunIXkCl48tyQLf0j8NNlUWoBpSr/HwwWy/LNwCq/d+Z63xdJvInK1w00fZ7/FLdfXNxU2dB66frxW61IvxvoN0kcp8VvL+83MMxGFo9a8dynhru7bicwSkUeyO5lT7y64QbiLucdS7d4LLLvWbENl+96hUkK33lCcWe4herLkL7A+AWmyRbVw0/hUS11BY/NWzXwqlWWLWuDvit0S2Evdk1XX4x+KT+6YcQUzgCYIXrFxA9eiYEwf2wysUzQ56ZDNwwW0UAfoxohnKfVXfTbovw/b2WGC2abNI2jKRrCNUxGr/g+6uCMfgaV5S/HpZRA3pZBCp9WrpddvyH8oUrL9AV94q2Kfs0kEiBVHhddvE3jrELZ4du8t/pkjR4PosV9fnULdq+pS3inHLSIWVH2IitNZ4YC+gi25WWcpMt4EUdueFeVTnIwwqwFhRwm+B6kf2bFI1BefcV3ItSx2q3s8mvZwDp1k3ScMQwqiOII4rJPQdbvvA6MfFzDC931OvCKwrJK9opvME23Je25mzRGRVX37+NMYnm9ZqGs403iYbYqBwb1YwHxiBtFWTZCraJLYOimwStJfCdBSu8LUutt5C2TOELjmPSHp5fA93PVwpDykHBQB3igmsdRivUza2uOVOAmDuMkf3NmGzTPy1Uoib/D2h3fnJnAPBWW5V0NEASrqyzBahzQ6jL41ehLGXw4Q1D3rppwgCZYYAR61AX7vPytflj+Bhz+VmTzd/4o+jB3W6uwioMoXddafsgKKoWxSYXBvlol8aLBSv67nompBOiLHrJxnPowRY5pfKUIcYpQee54ZwxhXT08PkMYHIYA5/LwerPpGzTsFzFVapoMi096VdFZL5CAM0NlJPjp4Zfx9Onu8dfx/fT5z05gWANhgbuzQ01lkSYKqlKOyshUbIcQ5RC3cZhlZkyvRmmICcgWCi4oH6pkf6iFpxWxfA3Xwu/ro0rpZjyfr2E6oDXzMB/BxFKSqo1quzZWulZXSFWuQuYGv6imUmZJNQm7NAI7O3X7vkNGdrWtXz3AJEAjm/kXeeEhGl83LTdf5nezv4Y/Hu7mw29Ta/L25f1lqKrah3BJdatVY/fXB/YBGk4/rSuUjjfA8BhF5wVjZdhV303daRA12UyJr5iivqPP6eFFCXT9raAXkLVMskAC18HfZYA6A0qpc6g2mAzALc9fb/TsQ3cGw8ku8E967FnonwU6i0tTWjhdGaF5vU7SshR7NNTIVoea0wHb9zYhzHzLaZq40folSNOPGDZSBOaEtgf5c8KZDQzQagMOcFYtck6oGYJzQim+KsuKdV/18Ry+qpB3UDq0lWugyPZVzUN9VR3g0cQYxh6bXF9V18SMZNWOXA7RutAJ1mMU8tdon+z8buYhulX3Cg3pIUlRDjB7NQoJ9CDq/WVaBN+F9pxrEUzPhrN5RxbBEVxHkGERgNEJ5Y9sm0C4hqOGNIIr2JOY184Q0zgK2xjIdXALBz6kgxtYDLr9bLJyeU48VkwZTryq0mElvK5+oqlWTcqLN7rw4kFHELXAgLHCB0D0itCjEGozCH1LpvAyMYonmBIwahiKnFCvzUe6XEiaHUGSAKR9ICCtM8ytPjAijwqIGoZB6I9uUkmfdH3n1PompYunJQEAh6GX+SarcYHsgmcqMtjFcihTLSeOR7sVVANSyAajpSbSMF4gVDMUFIbBap2b4KW7gjn+4w1qZbJnCsUIlpoHQdUH0OLNgxzT0l1+tsTB8yDdJqlbc0xORhVvHReAZrkJ22U20zIPj8eblJgf1yLn6JZwjJ56rPOIO6LsdYmuAbMKz1+qL6fHzzm3Dw0ORtkkmgLLpFqU9kSGRihUKEzXGX1wOPpgSJgYq0on+TOtgS+rPYHm4wa4eOueqnI2H7u/hY/kfToP5jF64D/Z/6PX/7YFumbJz5JyA3RqHdhmkanqHGiqdFrDUfLtLYaJpmar9DKDl/0sZwGdNNq6yioCNs+yMxw1NtjVFcz9i1WDfmLYjBoAMTXQJHhuutaXGjyOP1+kDszn0GzIdracmSKJCkxF20sFhsXqAJ2Ld4wO2KxFmPz+/Pzl/09dOHFnX9E+yknD4hBf4jZM0yJEOsQB7xOnzZT3UMZAzrTCvXX++u7dPY4ffyTeb/Po67fn8BHN5Nk4LWdCN/feBNF/qNpx5c7RDyH1zK6qXMfsgkh13E1MyOB+W4qkmMYpnHlBw3CL5l/sNPHEaLFUFdp9aLu2rAI3iuVYC5oBJIRwSCMiwSdwSJQbhiG6Q86U4B026Nken7GQhhf78IrrRlwfBGGhbOj2+O0wW8LFsdUdARhSTNEuWIS11BLbGtCvMWLdm8iLf0LOMKgMccPURhpLGoDDGdqOXeSzxu6IkbPgnhMz3I97ZYSERGJf0Y7a+CDo257CHA5LFGcMH7Z3svtpZtoYVOQGEH+afXx0UFHlpUZ3FlRsQP7pG6Z6Qr5YKk6n3r6A/S9hfeqyPruubtO758TMuDQTrbFRqGSNXoWaU4rjitYDMEHdHyvZEh2tVGdfj2dF3A4IGavypk6lvg41KT7dUKecuiEzo5DirPGdWaW3sPS/YXWCo2cMD7VYFGdEathuH3gP6xMN6rEnsHRdtThk1UKyevCODuhq3aJBPXpzM3/61YyTdMNUdAHq6Go9oy1Msi945bveJcUYT5IS7UD0Hi9oEBR7Jsj499vpwx+fGRlwU3fqbiAxl9g/9zgmWNjgt+/x948K5Skj3Xaovc+qmMBw2alrT9QhHcz+yuIbWwJ+79SDB0YODz6jAfDfs+fMhR48XXyIxQVkpp7GMnRmKt5k0ENeasPIO+wYy9iAYGrkniBtcOq2vf4Xw/cER1tDHJI4sMSFwLKnw1e8U6MhADm2Tu2HZrwR7cCKkh4wGPakzagk2qOXAhCkW3tG11fNlqNppFGgJuaS1bLIL/N8FeFwDwmZNvZq8RG627Cpkc3i3LEejCXeG3rdxnllbB5jWyPqtNDdOUYHczSVjKl15JgaVIIH3rHVvPeNYminxZGVhzs2NSfxL2jDrVTmLUioLeXvkrbhNnzjdXPulWeb9/eqI+YELurstWN9YdWyOvKFgUoxraW194yuXx431zHTsgtf8GWVbv+dTGuey8clU7Z75F3ewlZf0U72WHLJ0c7GxIV+opYm5TsB2qcTJi2TaghnxEqmLBPw39PYL6u1fleUxa623d/dPiHWAU2ZGpni3GcUsydS2chP+7muCzqy99CRadpkWF5Oeu2Q5DgJp5yiy+pvuhXVqz+bp9/9Aw== -------------------------------------------------------------------------------- /lab6/spec/figs/sync_fifo_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab6/spec/figs/sync_fifo_diagram.png -------------------------------------------------------------------------------- /lab6/spec/figs/sync_fifo_read_operation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab6/spec/figs/sync_fifo_read_operation.png -------------------------------------------------------------------------------- /lab6/spec/figs/sync_fifo_write_operation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_sp22/fa4fc9dc56121231058ac7354da697427110149f/lab6/spec/figs/sync_fifo_write_operation.png -------------------------------------------------------------------------------- /lab6/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 | -------------------------------------------------------------------------------- /lab6/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 | -------------------------------------------------------------------------------- /lab6/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 | -------------------------------------------------------------------------------- /lab6/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 | -------------------------------------------------------------------------------- /lab6/src/fifo.v: -------------------------------------------------------------------------------- 1 | module fifo #( 2 | parameter WIDTH = 8, 3 | parameter DEPTH = 32, 4 | parameter POINTER_WIDTH = $clog2(DEPTH) 5 | ) ( 6 | input clk, rst, 7 | 8 | // Write side 9 | input wr_en, 10 | input [WIDTH-1:0] din, 11 | output full, 12 | 13 | // Read side 14 | input rd_en, 15 | output [WIDTH-1:0] dout, 16 | output empty 17 | ); 18 | assign full = 1'b1; 19 | assign empty = 1'b0; 20 | assign dout = 0; 21 | endmodule 22 | -------------------------------------------------------------------------------- /lab6/src/fixed_length_piano.v: -------------------------------------------------------------------------------- 1 | module fixed_length_piano #( 2 | parameter CYCLES_PER_SECOND = 125_000_000 3 | ) ( 4 | input clk, 5 | input rst, 6 | 7 | input [2:0] buttons, 8 | output [5:0] leds, 9 | 10 | output [7:0] ua_tx_din, 11 | output ua_tx_wr_en, 12 | input ua_tx_full, 13 | 14 | input [7:0] ua_rx_dout, 15 | input ua_rx_empty, 16 | output ua_rx_rd_en, 17 | 18 | output [23:0] fcw 19 | ); 20 | assign fcw = 'd0; 21 | assign ua_tx_din = 0; 22 | assign ua_tx_wr_en = 0; 23 | assign ua_rx_rd_en = 0; 24 | endmodule 25 | -------------------------------------------------------------------------------- /lab6/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 | -------------------------------------------------------------------------------- /lab6/src/piano_scale_rom.v: -------------------------------------------------------------------------------- 1 | module piano_scale_rom (input [7:0] address, output reg [23:0] data, output [7:0] last_address); 2 | assign last_address = 255; 3 | always @ (*) begin 4 | case(address) 5 | 8'd0: data = 24'd0; 6 | 8'd1: data = 24'd0; 7 | 8'd2: data = 24'd0; 8 | 8'd3: data = 24'd0; 9 | 8'd4: data = 24'd0; 10 | 8'd5: data = 24'd0; 11 | 8'd6: data = 24'd0; 12 | 8'd7: data = 24'd0; 13 | 8'd8: data = 24'd0; 14 | 8'd9: data = 24'd0; 15 | 8'd10: data = 24'd0; 16 | 8'd11: data = 24'd0; 17 | 8'd12: data = 24'd0; 18 | 8'd13: data = 24'd0; 19 | 8'd14: data = 24'd0; 20 | 8'd15: data = 24'd0; 21 | 8'd16: data = 24'd0; 22 | 8'd17: data = 24'd0; 23 | 8'd18: data = 24'd0; 24 | 8'd19: data = 24'd0; 25 | 8'd20: data = 24'd0; 26 | 8'd21: data = 24'd0; 27 | 8'd22: data = 24'd0; 28 | 8'd23: data = 24'd0; 29 | 8'd24: data = 24'd0; 30 | 8'd25: data = 24'd0; 31 | 8'd26: data = 24'd0; 32 | 8'd27: data = 24'd0; 33 | 8'd28: data = 24'd0; 34 | 8'd29: data = 24'd0; 35 | 8'd30: data = 24'd0; 36 | 8'd31: data = 24'd0; 37 | 8'd32: data = 24'd0; 38 | 8'd33: data = 24'd0; 39 | 8'd34: data = 24'd0; 40 | 8'd35: data = 24'd85522; 41 | 8'd36: data = 24'd0; 42 | 8'd37: data = 24'd101703; 43 | 8'd38: data = 24'd128138; 44 | 8'd39: data = 24'd0; 45 | 8'd40: data = 24'd0; 46 | 8'd41: data = 24'd0; 47 | 8'd42: data = 24'd0; 48 | 8'd43: data = 24'd0; 49 | 8'd44: data = 24'd35958; 50 | 8'd45: data = 24'd0; 51 | 8'd46: data = 24'd0; 52 | 8'd47: data = 24'd0; 53 | 8'd48: data = 24'd0; 54 | 8'd49: data = 24'd0; 55 | 8'd50: data = 24'd38096; 56 | 8'd51: data = 24'd42761; 57 | 8'd52: data = 24'd0; 58 | 8'd53: data = 24'd50852; 59 | 8'd54: data = 24'd57079; 60 | 8'd55: data = 24'd64069; 61 | 8'd56: data = 24'd0; 62 | 8'd57: data = 24'd0; 63 | 8'd58: data = 24'd0; 64 | 8'd59: data = 24'd0; 65 | 8'd60: data = 24'd17979; 66 | 8'd61: data = 24'd0; 67 | 8'd62: data = 24'd0; 68 | 8'd63: data = 24'd0; 69 | 8'd64: data = 24'd76191; 70 | 8'd65: data = 24'd0; 71 | 8'd66: data = 24'd13469; 72 | 8'd67: data = 24'd11326; 73 | 8'd68: data = 24'd10690; 74 | 8'd69: data = 24'd90607; 75 | 8'd70: data = 24'd0; 76 | 8'd71: data = 24'd12713; 77 | 8'd72: data = 24'd14270; 78 | 8'd73: data = 24'd143830; 79 | 8'd74: data = 24'd16017; 80 | 8'd75: data = 24'd0; 81 | 8'd76: data = 24'd0; 82 | 8'd77: data = 24'd16970; 83 | 8'd78: data = 24'd15118; 84 | 8'd79: data = 24'd0; 85 | 8'd80: data = 24'd0; 86 | 8'd81: data = 24'd71915; 87 | 8'd82: data = 24'd95995; 88 | 8'd83: data = 24'd9524; 89 | 8'd84: data = 24'd107751; 90 | 8'd85: data = 24'd135758; 91 | 8'd86: data = 24'd11999; 92 | 8'd87: data = 24'd80722; 93 | 8'd88: data = 24'd10090; 94 | 8'd89: data = 24'd120946; 95 | 8'd90: data = 24'd8989; 96 | 8'd91: data = 24'd0; 97 | 8'd92: data = 24'd0; 98 | 8'd93: data = 24'd0; 99 | 8'd94: data = 24'd114158; 100 | 8'd95: data = 24'd0; 101 | 8'd96: data = 24'd0; 102 | 8'd97: data = 24'd0; 103 | 8'd98: data = 24'd26938; 104 | 8'd99: data = 24'd22652; 105 | 8'd100: data = 24'd21380; 106 | 8'd101: data = 24'd45304; 107 | 8'd102: data = 24'd0; 108 | 8'd103: data = 24'd25426; 109 | 8'd104: data = 24'd28539; 110 | 8'd105: data = 24'd71915; 111 | 8'd106: data = 24'd32035; 112 | 8'd107: data = 24'd0; 113 | 8'd108: data = 24'd0; 114 | 8'd109: data = 24'd33939; 115 | 8'd110: data = 24'd30237; 116 | 8'd111: data = 24'd0; 117 | 8'd112: data = 24'd0; 118 | 8'd113: data = 24'd35958; 119 | 8'd114: data = 24'd47998; 120 | 8'd115: data = 24'd19048; 121 | 8'd116: data = 24'd53756; 122 | 8'd117: data = 24'd67879; 123 | 8'd118: data = 24'd23999; 124 | 8'd119: data = 24'd40361; 125 | 8'd120: data = 24'd20180; 126 | 8'd121: data = 24'd60473; 127 | 8'd122: data = 24'd17979; 128 | 8'd123: data = 24'd0; 129 | 8'd124: data = 24'd0; 130 | 8'd125: data = 24'd0; 131 | 8'd126: data = 24'd0; 132 | 8'd127: data = 24'd0; 133 | 8'd128: data = 24'd0; 134 | 8'd129: data = 24'd0; 135 | 8'd130: data = 24'd0; 136 | 8'd131: data = 24'd0; 137 | 8'd132: data = 24'd0; 138 | 8'd133: data = 24'd0; 139 | 8'd134: data = 24'd0; 140 | 8'd135: data = 24'd0; 141 | 8'd136: data = 24'd0; 142 | 8'd137: data = 24'd0; 143 | 8'd138: data = 24'd0; 144 | 8'd139: data = 24'd0; 145 | 8'd140: data = 24'd0; 146 | 8'd141: data = 24'd0; 147 | 8'd142: data = 24'd0; 148 | 8'd143: data = 24'd0; 149 | 8'd144: data = 24'd0; 150 | 8'd145: data = 24'd0; 151 | 8'd146: data = 24'd0; 152 | 8'd147: data = 24'd0; 153 | 8'd148: data = 24'd0; 154 | 8'd149: data = 24'd0; 155 | 8'd150: data = 24'd0; 156 | 8'd151: data = 24'd0; 157 | 8'd152: data = 24'd0; 158 | 8'd153: data = 24'd0; 159 | 8'd154: data = 24'd0; 160 | 8'd155: data = 24'd0; 161 | 8'd156: data = 24'd0; 162 | 8'd157: data = 24'd0; 163 | 8'd158: data = 24'd0; 164 | 8'd159: data = 24'd0; 165 | 8'd160: data = 24'd0; 166 | 8'd161: data = 24'd0; 167 | 8'd162: data = 24'd0; 168 | 8'd163: data = 24'd0; 169 | 8'd164: data = 24'd0; 170 | 8'd165: data = 24'd0; 171 | 8'd166: data = 24'd0; 172 | 8'd167: data = 24'd0; 173 | 8'd168: data = 24'd0; 174 | 8'd169: data = 24'd0; 175 | 8'd170: data = 24'd0; 176 | 8'd171: data = 24'd0; 177 | 8'd172: data = 24'd0; 178 | 8'd173: data = 24'd0; 179 | 8'd174: data = 24'd0; 180 | 8'd175: data = 24'd0; 181 | 8'd176: data = 24'd0; 182 | 8'd177: data = 24'd0; 183 | 8'd178: data = 24'd0; 184 | 8'd179: data = 24'd0; 185 | 8'd180: data = 24'd0; 186 | 8'd181: data = 24'd0; 187 | 8'd182: data = 24'd0; 188 | 8'd183: data = 24'd0; 189 | 8'd184: data = 24'd0; 190 | 8'd185: data = 24'd0; 191 | 8'd186: data = 24'd0; 192 | 8'd187: data = 24'd0; 193 | 8'd188: data = 24'd0; 194 | 8'd189: data = 24'd0; 195 | 8'd190: data = 24'd0; 196 | 8'd191: data = 24'd0; 197 | 8'd192: data = 24'd0; 198 | 8'd193: data = 24'd0; 199 | 8'd194: data = 24'd0; 200 | 8'd195: data = 24'd0; 201 | 8'd196: data = 24'd0; 202 | 8'd197: data = 24'd0; 203 | 8'd198: data = 24'd0; 204 | 8'd199: data = 24'd0; 205 | 8'd200: data = 24'd0; 206 | 8'd201: data = 24'd0; 207 | 8'd202: data = 24'd0; 208 | 8'd203: data = 24'd0; 209 | 8'd204: data = 24'd0; 210 | 8'd205: data = 24'd0; 211 | 8'd206: data = 24'd0; 212 | 8'd207: data = 24'd0; 213 | 8'd208: data = 24'd0; 214 | 8'd209: data = 24'd0; 215 | 8'd210: data = 24'd0; 216 | 8'd211: data = 24'd0; 217 | 8'd212: data = 24'd0; 218 | 8'd213: data = 24'd0; 219 | 8'd214: data = 24'd0; 220 | 8'd215: data = 24'd0; 221 | 8'd216: data = 24'd0; 222 | 8'd217: data = 24'd0; 223 | 8'd218: data = 24'd0; 224 | 8'd219: data = 24'd0; 225 | 8'd220: data = 24'd0; 226 | 8'd221: data = 24'd0; 227 | 8'd222: data = 24'd0; 228 | 8'd223: data = 24'd0; 229 | 8'd224: data = 24'd0; 230 | 8'd225: data = 24'd0; 231 | 8'd226: data = 24'd0; 232 | 8'd227: data = 24'd0; 233 | 8'd228: data = 24'd0; 234 | 8'd229: data = 24'd0; 235 | 8'd230: data = 24'd0; 236 | 8'd231: data = 24'd0; 237 | 8'd232: data = 24'd0; 238 | 8'd233: data = 24'd0; 239 | 8'd234: data = 24'd0; 240 | 8'd235: data = 24'd0; 241 | 8'd236: data = 24'd0; 242 | 8'd237: data = 24'd0; 243 | 8'd238: data = 24'd0; 244 | 8'd239: data = 24'd0; 245 | 8'd240: data = 24'd0; 246 | 8'd241: data = 24'd0; 247 | 8'd242: data = 24'd0; 248 | 8'd243: data = 24'd0; 249 | 8'd244: data = 24'd0; 250 | 8'd245: data = 24'd0; 251 | 8'd246: data = 24'd0; 252 | 8'd247: data = 24'd0; 253 | 8'd248: data = 24'd0; 254 | 8'd249: data = 24'd0; 255 | 8'd250: data = 24'd0; 256 | 8'd251: data = 24'd0; 257 | 8'd252: data = 24'd0; 258 | 8'd253: data = 24'd0; 259 | 8'd254: data = 24'd0; 260 | 8'd255: data = 24'd0; 261 | endcase 262 | end 263 | endmodule 264 | -------------------------------------------------------------------------------- /lab6/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 | -------------------------------------------------------------------------------- /lab6/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 | -------------------------------------------------------------------------------- /lab6/src/uart.v: -------------------------------------------------------------------------------- 1 | module uart #( 2 | parameter CLOCK_FREQ = 125_000_000, 3 | parameter BAUD_RATE = 115_200 4 | ) ( 5 | input clk, 6 | input reset, 7 | 8 | input [7:0] data_in, 9 | input data_in_valid, 10 | output data_in_ready, 11 | 12 | output [7:0] data_out, 13 | output data_out_valid, 14 | input data_out_ready, 15 | 16 | input serial_in, 17 | output serial_out 18 | ); 19 | reg serial_in_reg, serial_out_reg; 20 | wire serial_out_tx; 21 | assign serial_out = serial_out_reg; 22 | always @ (posedge clk) begin 23 | serial_out_reg <= reset ? 1'b1 : serial_out_tx; 24 | serial_in_reg <= reset ? 1'b1 : serial_in; 25 | end 26 | 27 | uart_transmitter #( 28 | .CLOCK_FREQ(CLOCK_FREQ), 29 | .BAUD_RATE(BAUD_RATE) 30 | ) uatransmit ( 31 | .clk(clk), 32 | .reset(reset), 33 | .data_in(data_in), 34 | .data_in_valid(data_in_valid), 35 | .data_in_ready(data_in_ready), 36 | .serial_out(serial_out_tx) 37 | ); 38 | 39 | uart_receiver #( 40 | .CLOCK_FREQ(CLOCK_FREQ), 41 | .BAUD_RATE(BAUD_RATE) 42 | ) uareceive ( 43 | .clk(clk), 44 | .reset(reset), 45 | .data_out(data_out), 46 | .data_out_valid(data_out_valid), 47 | .data_out_ready(data_out_ready), 48 | .serial_in(serial_in_reg) 49 | ); 50 | endmodule 51 | -------------------------------------------------------------------------------- /lab6/src/uart_receiver.v: -------------------------------------------------------------------------------- 1 | module uart_receiver #( 2 | parameter CLOCK_FREQ = 125_000_000, 3 | parameter BAUD_RATE = 115_200) 4 | ( 5 | input clk, 6 | input reset, 7 | 8 | output [7:0] data_out, 9 | output data_out_valid, 10 | input data_out_ready, 11 | 12 | input serial_in 13 | ); 14 | // See diagram in the lab guide 15 | localparam SYMBOL_EDGE_TIME = CLOCK_FREQ / BAUD_RATE; 16 | localparam SAMPLE_TIME = SYMBOL_EDGE_TIME / 2; 17 | localparam CLOCK_COUNTER_WIDTH= $clog2(SYMBOL_EDGE_TIME); 18 | 19 | wire symbol_edge; 20 | wire sample; 21 | wire start; 22 | wire rx_running; 23 | 24 | reg [9:0] rx_shift; 25 | reg [3:0] bit_counter; 26 | reg [CLOCK_COUNTER_WIDTH-1:0] clock_counter; 27 | reg has_byte; 28 | 29 | //--|Signal Assignments|------------------------------------------------------ 30 | 31 | // Goes high at every symbol edge 32 | /* verilator lint_off WIDTH */ 33 | assign symbol_edge = clock_counter == (SYMBOL_EDGE_TIME - 1); 34 | /* lint_on */ 35 | 36 | // Goes high halfway through each symbol 37 | /* verilator lint_off WIDTH */ 38 | assign sample = clock_counter == SAMPLE_TIME; 39 | /* lint_on */ 40 | 41 | // Goes high when it is time to start receiving a new character 42 | assign start = !serial_in && !rx_running; 43 | 44 | // Goes high while we are receiving a character 45 | assign rx_running = bit_counter != 4'd0; 46 | 47 | // Outputs 48 | assign data_out = rx_shift[8:1]; 49 | assign data_out_valid = has_byte && !rx_running; 50 | 51 | //--|Counters|---------------------------------------------------------------- 52 | 53 | // Counts cycles until a single symbol is done 54 | always @ (posedge clk) begin 55 | clock_counter <= (start || reset || symbol_edge) ? 0 : clock_counter + 1; 56 | end 57 | 58 | // Counts down from 10 bits for every character 59 | always @ (posedge clk) begin 60 | if (reset) begin 61 | bit_counter <= 0; 62 | end else if (start) begin 63 | bit_counter <= 10; 64 | end else if (symbol_edge && rx_running) begin 65 | bit_counter <= bit_counter - 1; 66 | end 67 | end 68 | 69 | //--|Shift Register|---------------------------------------------------------- 70 | always @(posedge clk) begin 71 | if (sample && rx_running) rx_shift <= {serial_in, rx_shift[9:1]}; 72 | end 73 | 74 | //--|Extra State For Ready/Valid|--------------------------------------------- 75 | // This block and the has_byte signal aren't needed in the uart_transmitter 76 | always @ (posedge clk) begin 77 | if (reset) has_byte <= 1'b0; 78 | else if (bit_counter == 1 && symbol_edge) has_byte <= 1'b1; 79 | else if (data_out_ready) has_byte <= 1'b0; 80 | end 81 | endmodule 82 | -------------------------------------------------------------------------------- /lab6/src/uart_transmitter.v: -------------------------------------------------------------------------------- 1 | module uart_transmitter #( 2 | parameter CLOCK_FREQ = 125_000_000, 3 | parameter BAUD_RATE = 115_200) 4 | ( 5 | input clk, 6 | input reset, 7 | 8 | input [7:0] data_in, 9 | input data_in_valid, 10 | output data_in_ready, 11 | 12 | output serial_out 13 | ); 14 | // See diagram in the lab guide 15 | localparam SYMBOL_EDGE_TIME = CLOCK_FREQ / BAUD_RATE; 16 | localparam CLOCK_COUNTER_WIDTH = $clog2(SYMBOL_EDGE_TIME); 17 | 18 | // Remove these assignments when implementing this module 19 | assign serial_out = 1'b0; 20 | assign data_in_ready = 1'b0; 21 | endmodule 22 | -------------------------------------------------------------------------------- /lab6/src/variable_length_piano.v: -------------------------------------------------------------------------------- 1 | module variable_length_piano ( 2 | input clk, 3 | input rst, 4 | 5 | input [2:0] buttons, 6 | output [5:0] leds, 7 | 8 | output [7:0] ua_tx_din, 9 | output ua_tx_wr_en, 10 | input ua_tx_full, 11 | 12 | input [7:0] ua_rx_dout, 13 | input ua_rx_empty, 14 | output ua_rx_rd_en, 15 | 16 | output [23:0] fcw 17 | ); 18 | assign fcw = 'd0; 19 | assign ua_tx_din = 0; 20 | assign ua_tx_wr_en = 0; 21 | assign ua_rx_rd_en = 0; 22 | endmodule 23 | -------------------------------------------------------------------------------- /lab6/src/z1top.v: -------------------------------------------------------------------------------- 1 | module z1top #( 2 | parameter CLOCK_FREQ = 125_000_000, 3 | parameter BAUD_RATE = 115_200, 4 | /* verilator lint_off REALCVT */ 5 | // Sample the button signal every 500us 6 | parameter integer B_SAMPLE_CNT_MAX = 0.0005 * CLOCK_FREQ, 7 | // The button is considered 'pressed' after 100ms of continuous pressing 8 | parameter integer B_PULSE_CNT_MAX = 0.100 / 0.0005, 9 | /* lint_on */ 10 | parameter CYCLES_PER_SECOND = 125_000_000 11 | ) ( 12 | input CLK_125MHZ_FPGA, 13 | input [3:0] BUTTONS, 14 | input [1:0] SWITCHES, 15 | output [5:0] LEDS, 16 | output AUD_PWM, 17 | output AUD_SD, 18 | input FPGA_SERIAL_RX, 19 | output FPGA_SERIAL_TX 20 | ); 21 | assign AUD_SD = 1; // Enable the audio output 22 | 23 | wire [2:0] buttons_pressed; 24 | wire [1:0] switches_sync; 25 | wire reset; 26 | button_parser #( 27 | .WIDTH(4), 28 | .SAMPLE_CNT_MAX(B_SAMPLE_CNT_MAX), 29 | .PULSE_CNT_MAX(B_PULSE_CNT_MAX) 30 | ) bp ( 31 | .clk(CLK_125MHZ_FPGA), 32 | .in(BUTTONS), 33 | .out({buttons_pressed, reset}) 34 | ); 35 | 36 | synchronizer #(.WIDTH(2)) switch_sync ( 37 | .clk(CLK_125MHZ_FPGA), 38 | .async_signal(SWITCHES), 39 | .sync_signal(switches_sync) 40 | ); 41 | 42 | reg [7:0] data_in; 43 | wire [7:0] data_out; 44 | wire data_in_valid, data_in_ready, data_out_valid, data_out_ready; 45 | 46 | // This UART is on the FPGA and communicates with your desktop 47 | // using the FPGA_SERIAL_TX, and FPGA_SERIAL_RX signals. The ready/valid 48 | // interface for this UART is used on the FPGA design. 49 | uart # ( 50 | .CLOCK_FREQ(CLOCK_FREQ), 51 | .BAUD_RATE(BAUD_RATE) 52 | ) on_chip_uart ( 53 | .clk(CLK_125MHZ_FPGA), 54 | .reset(reset), 55 | .data_in(data_in), 56 | .data_in_valid(data_in_valid), 57 | .data_in_ready(data_in_ready), 58 | .data_out(data_out), 59 | .data_out_valid(data_out_valid), 60 | .data_out_ready(data_out_ready), 61 | .serial_in(FPGA_SERIAL_RX), 62 | .serial_out(FPGA_SERIAL_TX) 63 | ); 64 | 65 | //// TODO: Instantiate the UART FIFOs, nco, dac, and piano 66 | assign AUD_PWM = 0; // Comment this out when ready 67 | assign LEDS[5:0] = 6'b11_0001; // Connect to the leds output of the piano 68 | endmodule 69 | -------------------------------------------------------------------------------- /lab6/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 | 37 | ##Pmod Header JA 38 | #set_property -dict { PACKAGE_PIN Y18 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_L17P_T2_34 Sch=ja_p[1] 39 | set_property -dict { PACKAGE_PIN Y19 IOSTANDARD LVCMOS33 } [get_ports { FPGA_SERIAL_TX }]; #IO_L17N_T2_34 Sch=ja_n[1] 40 | set_property -dict { PACKAGE_PIN Y16 IOSTANDARD LVCMOS33 } [get_ports { FPGA_SERIAL_RX }]; #IO_L7P_T1_34 Sch=ja_p[2] 41 | #set_property -dict { PACKAGE_PIN Y17 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L7N_T1_34 Sch=ja_n[2] 42 | #set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L12P_T1_MRCC_34 Sch=ja_p[3] 43 | #set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L12N_T1_MRCC_34 Sch=ja_n[3] 44 | #set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22P_T3_34 Sch=ja_p[4] 45 | #set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22N_T3_34 Sch=ja_n[4] 46 | -------------------------------------------------------------------------------- /scripts/audio_from_sim: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | This script converts a raw square wave signal from a Verilog simulation into a .wav audio file for playback. 4 | 5 | Usage: ./scripts/audio_from_sim lab3/sim/codes.txt 6 | 7 | This script will generate a file named output.wav that can be played using 'play' 8 | Playback: play output.wav 9 | """ 10 | 11 | import wave 12 | import random 13 | import struct 14 | import sys 15 | 16 | filepath = sys.argv[1] 17 | values = [] 18 | 19 | def renormalize(n, range1, range2): 20 | delta1 = range1[1] - range1[0] 21 | delta2 = range2[1] - range2[0] 22 | return (delta2 * (n - range1[0]) / delta1) + range2[0] 23 | 24 | with open(filepath, 'r') as samples_file: 25 | values = [int(line.rstrip('\n').strip()) for line in samples_file] 26 | values_scaled = [renormalize(s, (0, 1023), (-2**15, 2**15-1)) for s in values] 27 | #max_value = max(values) 28 | #scaled_values = [((val*40000) / max_value) + -20000 for val in values] 29 | packed_values = [struct.pack(' 0): 55 | duration = int(note.getElementsByTagName('duration')[0].childNodes[0].nodeValue) 56 | print("\trest note, duration %d" % (duration)) 57 | notes += [(0, 0, 0, duration)] 58 | else: 59 | note_pitch = note.getElementsByTagName('pitch').item(0) 60 | step = note_pitch.getElementsByTagName('step')[0].childNodes[0].nodeValue 61 | octave = int(note_pitch.getElementsByTagName('octave')[0].childNodes[0].nodeValue) 62 | alter = note_pitch.getElementsByTagName('alter') 63 | if (len(alter) > 0): 64 | alter = int(alter[0].childNodes[0].nodeValue) 65 | else: 66 | alter = 0 67 | duration = int(note.getElementsByTagName('duration')[0].childNodes[0].nodeValue) 68 | note_type = note.getElementsByTagName('type')[0].childNodes[0].nodeValue 69 | print("\tnote with step %s octave %d alter %d duration %d type %s" % (step, octave, alter, duration, note_type)) 70 | notes += [(step, octave, alter, duration)] 71 | 72 | note_list = [] 73 | for note in notes: 74 | if (note[0] == 0): 75 | note_list += [(0, note[3])] 76 | else: 77 | semitone_above_below_middle_C = step_to_int[note[0]] - step_to_int['C'] + note[2] 78 | if (step_to_int[note[0]] >= step_to_int['C']): 79 | note_number = semitone_above_below_middle_C + ((note[1] - 4) * 12) 80 | else: 81 | note_number = semitone_above_below_middle_C + ((note[1] - 3) * 12) 82 | note_number = note_number + 40 83 | frequency = (2 ** ((float(note_number) - 49.0)/12.0)) * 440.0 84 | note_list += [(int(frequency), note[3])] 85 | 86 | print("note_list (frequency, duration)\n") 87 | print(note_list) 88 | 89 | # Translate each note to the equivalent frequency and to the individual half-periods of 32nd notes 90 | with open(memory_contents_filepath, 'w') as memory_file: 91 | for note in note_list: 92 | if (note[0] == 0): 93 | for i in range(0, 4 * note[1]): 94 | memory_file.write(str(0) + "\n") 95 | continue 96 | # Write the note in terms of tone_switch_period (125 Mhz clock) 97 | for i in range(0, 4 * note[1]): 98 | memory_file.write(str(int(125e6/note[0]/2)) + "\n") 99 | # Write a note pause for each note corresponding to its duration 100 | for i in range(0, note[1]): 101 | memory_file.write(str(0) + "\n") 102 | 103 | # Remove the temp directory from current run 104 | if (os.path.isdir('temp/')): 105 | shutil.rmtree('temp/') 106 | -------------------------------------------------------------------------------- /scripts/piano: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from pynput.keyboard import Key, Listener 4 | import os 5 | import serial 6 | 7 | 8 | if os.name == 'nt': 9 | print('Windows machine!') 10 | ser = serial.Serial() 11 | ser.baudrate = 115200 12 | ser.port = 'COM11' # CHANGE THIS COM PORT 13 | ser.open() 14 | else: 15 | print('Not windows machine!') 16 | ser = serial.Serial('/dev/ttyUSB0') 17 | ser.baudrate = 115200 18 | 19 | #keys_pressed = set() 20 | active_key = None 21 | 22 | def start_playing(key): 23 | ser.write(bytearray([0x80])) 24 | ser.write(bytearray([ord(key.char)])) 25 | 26 | def stop_playing(key): 27 | ser.write(bytearray([0x81])) 28 | ser.write(bytearray([ord(key.char)])) 29 | 30 | def on_press(key): 31 | global active_key 32 | if key == Key.esc: 33 | if active_key is not None: 34 | stop_playing(active_key) 35 | # Stop listener 36 | return False 37 | 38 | # Stop playing already active key 39 | if active_key is not None and key.char is not active_key.char: 40 | stop_playing(active_key) 41 | 42 | if active_key is None or active_key.char is not key.char: 43 | active_key = key 44 | start_playing(key) 45 | print('{0} pressed'.format(key)) 46 | """ 47 | if key not in keys_pressed: 48 | ser.write(bytearray([0x80])) 49 | ser.write(bytearray([ord(key.char)])) 50 | keys_pressed.add(key) 51 | """ 52 | 53 | def on_release(key): 54 | global active_key 55 | if active_key is not None and key.char == active_key.char: 56 | stop_playing(active_key) 57 | active_key = None 58 | 59 | print('{0} release'.format(key)) 60 | """ 61 | if key in keys_pressed: 62 | keys_pressed.remove(key) 63 | ser.write(bytearray([0x81])) 64 | ser.write(bytearray([ord(key.char)])) 65 | if key == Key.esc: 66 | # Stop listener 67 | return False 68 | """ 69 | 70 | # Collect events until released 71 | with Listener( 72 | on_press=on_press, 73 | on_release=on_release, 74 | suppress=True) as listener: 75 | listener.join() 76 | -------------------------------------------------------------------------------- /scripts/piano_scale_generator: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import wave 4 | import random 5 | import struct 6 | import sys 7 | import math 8 | 9 | """ 10 | This script will generate a text file to be fed into the rom_generator.py script. 11 | It will print out the keyboard letter mappings in ASCII to piano notes. The piano notes 12 | are stored in terms of tone_switch_periods for a given clock frequency. 13 | """ 14 | output_file = sys.argv[1] 15 | # Can supply custom clock frequency, otherwise defaults to 125 Mhz 16 | if len(sys.argv) > 2: 17 | clock_freq = float(sys.argv[2]) 18 | else: 19 | clock_freq = 125.0e6 20 | 21 | note_map = { 22 | 'Z': 65.4064, 23 | 'S': 69.2957, 24 | 'X': 73.4162, 25 | 'D': 77.7817, 26 | 'C': 82.4069, 27 | 'V': 87.3071, 28 | 'G': 92.4986, 29 | 'B': 97.9989, 30 | 'H': 103.826, 31 | 'N': 110.000, 32 | 'J': 116.541, 33 | 'M': 123.471, 34 | '<': 130.813, 35 | 36 | 'z': 130.813, 37 | 's': 138.591, 38 | 'x': 146.832, 39 | 'd': 155.563, 40 | 'c': 164.814, 41 | 'v': 174.614, 42 | 'g': 184.997, 43 | 'b': 195.998, 44 | 'h': 207.652, 45 | 'n': 220.000, 46 | 'j': 233.082, 47 | 'm': 246.942, 48 | ',': 261.626, 49 | 50 | 'q': 261.626, 51 | '2': 277.183, 52 | 'w': 293.665, 53 | '3': 311.127, 54 | 'e': 329.628, 55 | 'r': 349.228, 56 | '5': 369.994, 57 | 't': 391.127, 58 | '6': 415.305, 59 | 'y': 440.000, 60 | '7': 466.164, 61 | 'u': 493.883, 62 | 'i': 523.251, 63 | 64 | 'Q': 523.251, 65 | '@': 554.365, 66 | 'W': 587.330, 67 | '#': 622.254, 68 | 'E': 659.255, 69 | 'R': 698.456, 70 | '%': 739.989, 71 | 'T': 783.991, 72 | '^': 830.609, 73 | 'Y': 880.000, 74 | '&': 932.328, 75 | 'U': 987.767, 76 | 'I': 1046.50 77 | } 78 | 79 | piano_output_file = open(output_file, 'w') 80 | for ascii_index in range(256): 81 | if chr(ascii_index) in note_map: 82 | note_freq = note_map[chr(ascii_index)] 83 | note_fcw = (note_freq / (125e6 / 1024)) * (2**24) 84 | piano_output_file.write(str(int(round(note_fcw))) + "\n") 85 | else: 86 | piano_output_file.write("0\n") 87 | 88 | piano_output_file.close() 89 | -------------------------------------------------------------------------------- /scripts/program.tcl: -------------------------------------------------------------------------------- 1 | source ../target.tcl 2 | open_hw 3 | 4 | connect_hw_server -url localhost:3121 5 | current_hw_target [get_hw_targets */xilinx_tcf/Digilent/*] 6 | set_property PARAM.FREQUENCY 15000000 [get_hw_targets */xilinx_tcf/Digilent/*] 7 | open_hw_target 8 | 9 | current_hw_device [get_hw_devices xc7z*] 10 | set_property PROBES.FILE {} [get_hw_devices xc7z*] 11 | set_property FULL_PROBES.FILE {} [get_hw_devices xc7z*] 12 | 13 | # Hack to expand ${ABS_TOP} and ${TOP} properly, running set_property directly doesn't expand these variables 14 | set set_cmd "set_property PROGRAM.FILE \{${ABS_TOP}/build/impl/${TOP}.bit\} \[get_hw_devices xc7z*\]" 15 | eval ${set_cmd} 16 | program_hw_devices [get_hw_devices xc7z*] 17 | refresh_hw_device [get_hw_devices xc7z*] 18 | 19 | close_hw 20 | -------------------------------------------------------------------------------- /scripts/program_2021.tcl: -------------------------------------------------------------------------------- 1 | source ../target.tcl 2 | open_hw_manager 3 | 4 | connect_hw_server -url localhost:3121 -allow_non_jtag 5 | current_hw_target [get_hw_targets */xilinx_tcf/Digilent/*] 6 | set_property PARAM.FREQUENCY 15000000 [get_hw_targets */xilinx_tcf/Digilent/*] 7 | open_hw_target 8 | 9 | current_hw_device [get_hw_devices xc7z*] 10 | refresh_hw_device -update_hw_probes false [lindex [get_hw_devices xc7z*] 0] 11 | set_property PROBES.FILE {} [get_hw_devices xc7z020_1] 12 | set_property FULL_PROBES.FILE {} [get_hw_devices xc7z020_1] 13 | 14 | # Hack to expand ${ABS_TOP} and ${TOP} properly, running set_property directly doesn't expand these variables 15 | set set_cmd "set_property PROGRAM.FILE \{${ABS_TOP}/build/impl/${TOP}.bit\} \[get_hw_devices xc7z*\]" 16 | eval ${set_cmd} 17 | program_hw_devices [get_hw_devices xc7z*] 18 | refresh_hw_device [lindex [get_hw_devices xc7z*] 0] 19 | 20 | close_hw_manager 21 | 22 | # Raw TCL and log 23 | # start_gui 24 | # open_hw_manager 25 | # INFO: [IP_Flow 19-234] Refreshing IP repositories 26 | # INFO: [IP_Flow 19-1704] No user IP repositories specified 27 | # INFO: [IP_Flow 19-2313] Loaded Vivado IP repository '/opt/vivado/Vivado/2021.1/data/ip'. 28 | # open_hw_manager: Time (s): cpu = 00:00:14 ; elapsed = 00:00:05 . Memory (MB): peak = 7493.453 ; gain = 58.125 ; free physical = 12289 ; free virtual = 35691 29 | # connect_hw_server -url localhost:3121 -allow_non_jtag 30 | # INFO: [Labtools 27-2285] Connecting to hw_server url TCP:localhost:3121 31 | # INFO: [Labtools 27-3415] Connecting to cs_server url TCP:localhost:3042 32 | # INFO: [Labtools 27-3414] Connected to existing cs_server. 33 | # current_hw_target [get_hw_targets */xilinx_tcf/Digilent/003017A8B74BA] 34 | # set_property PARAM.FREQUENCY 15000000 [get_hw_targets */xilinx_tcf/Digilent/003017A8B74BA] 35 | # open_hw_target 36 | # INFO: [Labtoolstcl 44-466] Opening hw_target localhost:3121/xilinx_tcf/Digilent/003017A8B74BA 37 | # current_hw_device [get_hw_devices xc7z020_1] 38 | # refresh_hw_device -update_hw_probes false [lindex [get_hw_devices xc7z020_1] 0] 39 | # INFO: [Labtools 27-1434] Device xc7z020 (JTAG device index = 1) is programmed with a design that has no supported debug core(s) in it. 40 | # set_property PROBES.FILE {} [get_hw_devices xc7z020_1] 41 | # set_property FULL_PROBES.FILE {} [get_hw_devices xc7z020_1] 42 | # set_property PROGRAM.FILE {/home/vighnesh/10-school/12-secondary/19-eecs151/labs_skeleton/fpga_labs_fa21/lab1/build/impl/z1top.bit} [get_hw_devices xc7z020_1] 43 | # program_hw_devices [get_hw_devices xc7z020_1] 44 | # INFO: [Labtools 27-3164] End of startup status: HIGH 45 | # refresh_hw_device [lindex [get_hw_devices xc7z020_1] 0] 46 | # INFO: [Labtools 27-1434] Device xc7z020 (JTAG device index = 1) is programmed with a design that has no supported debug core(s) in it. 47 | # close_hw_manager 48 | # ****** Webtalk v2021.1 (64-bit) 49 | # **** SW Build 3247384 on Thu Jun 10 19:36:07 MDT 2021 50 | # **** IP Build 3246043 on Fri Jun 11 00:30:35 MDT 2021 51 | # ** Copyright 1986-2021 Xilinx, Inc. All Rights Reserved. 52 | # 53 | # source /home/vighnesh/10-school/12-secondary/19-eecs151/labs_skeleton/fpga_labs_fa21/lab1/build/.Xil/Vivado-186575-vighnesh-t480/webtalk/labtool_webtalk.tcl -notrace 54 | # INFO: [Common 17-186] '/home/vighnesh/10-school/12-secondary/19-eecs151/labs_skeleton/fpga_labs_fa21/lab1/build/.Xil/Vivado-186575-vighnesh-t480/webtalk/usage_statistics_ext_labtool.xml' has been successfully sent to Xilinx on Fri Aug 27 17:02:08 2021. For additional details about this file, please refer to the WebTalk help file at /opt/vivado/Vivado/2021.1/doc/webtalk_introduction.html. 55 | # INFO: [Common 17-206] Exiting Webtalk at Fri Aug 27 17:02:08 2021... 56 | # close_hw_manager: Time (s): cpu = 00:00:09 ; elapsed = 00:00:08 . Memory (MB): peak = 8461.398 ; gain = 7.219 ; free physical = 10648 ; free virtual = 34132 57 | -------------------------------------------------------------------------------- /scripts/rom_generator: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import wave 4 | import random 5 | import struct 6 | import sys 7 | import math 8 | 9 | generated_verilog_filepath = sys.argv[2] 10 | memory_file = sys.argv[1] 11 | memory_depth = int(sys.argv[3]) 12 | memory_width = int(sys.argv[4]) 13 | address_bits = int(math.ceil(math.log(memory_depth, 2))) 14 | data_bits = memory_width 15 | 16 | with open(memory_file, 'r') as memory_data: 17 | data = memory_data.read() 18 | 19 | data = data.split('\n') 20 | 21 | verilog_file = open(generated_verilog_filepath, 'w') 22 | verilog_file.write("module rom (input [%d:0] address, output reg [%d:0] data, output [%d:0] last_address);\n" % (address_bits - 1, data_bits - 1, address_bits - 1)) 23 | verilog_file.write(" assign last_address = %d;\n" % (min(len(data) - 1, memory_depth - 1))) 24 | verilog_file.write(" always @ (*) begin\n") 25 | verilog_file.write(" case(address)\n") 26 | 27 | for i in range(0, memory_depth): 28 | if (i >= len(data) or len(data[i]) == 0): # Write a 0 29 | verilog_file.write(" %d'd%d: data = %d'd%d;\n" % (address_bits, i, data_bits, 0)) 30 | else: 31 | verilog_file.write(" %d'd%d: data = %d'd%d;\n" % (address_bits, i, data_bits, int(data[i]))) 32 | 33 | verilog_file.write(" endcase\n") 34 | verilog_file.write(" end\n") 35 | verilog_file.write("endmodule\n") 36 | verilog_file.close() 37 | 38 | -------------------------------------------------------------------------------- /scripts/synth.tcl: -------------------------------------------------------------------------------- 1 | source ../target.tcl 2 | 3 | # Read Verilog source files 4 | if {[string trim ${RTL}] ne ""} { 5 | read_verilog -v ${RTL} 6 | } 7 | 8 | # Read user constraints 9 | if {[string trim ${CONSTRAINTS}] ne ""} { 10 | read_xdc ${CONSTRAINTS} 11 | } 12 | 13 | synth_design -top ${TOP} -part ${FPGA_PART} 14 | 15 | write_checkpoint -force ${TOP}.dcp 16 | report_timing_summary -file post_synth_timing_summary.rpt 17 | report_drc -file post_synth_drc.rpt 18 | report_utilization -file post_synth_utilization.rpt 19 | write_verilog -force -file post_synth.v 20 | write_xdc -force -file post_synth.xdc 21 | --------------------------------------------------------------------------------