├── lab1 ├── sim │ └── dummy_sim.v ├── Makefile ├── .DS_Store ├── spec │ └── figs │ │ ├── x2go_setup.png │ │ ├── vivado_options.png │ │ ├── z1_top_annotated.png │ │ └── z1_bottom_annotated.png └── src │ ├── z1top.v │ └── z1top.xdc ├── lab2 ├── Makefile ├── spec │ └── figs │ │ ├── dve.png │ │ └── dve_wave.png ├── src │ ├── behavioral_adder.v │ ├── structural_adder.v │ ├── full_adder.v │ ├── counter.v │ ├── adder_tester.v │ ├── z1top.v │ └── z1top.xdc └── sim │ ├── counter_testbench.v │ └── adder_testbench.v ├── lab3 ├── Makefile ├── spec │ └── figs │ │ ├── pwm.pdf │ │ ├── pwm.png │ │ ├── bouncing.png │ │ ├── audio_out.png │ │ ├── debouncer.png │ │ ├── metastability.png │ │ └── synchronizer.png ├── src │ ├── sq_wave_gen.v │ ├── dac.v │ ├── edge_detector.v │ ├── counter.v │ ├── synchronizer.v │ ├── debouncer.v │ ├── button_parser.v │ ├── z1top.v │ └── z1top.xdc └── sim │ ├── sq_wave_gen_tb.v │ ├── sync_tb.v │ ├── dac_tb.v │ ├── edge_detector_tb.v │ └── debouncer_tb.v ├── lab4 ├── Makefile ├── spec │ ├── figs │ │ ├── fsm.png │ │ ├── top.png │ │ └── lab4figs.pptx │ └── spec.md ├── src │ ├── nco.v │ ├── sq_wave_gen.v │ ├── dac.v │ ├── edge_detector.v │ ├── synchronizer.v │ ├── fsm.v │ ├── fcw_ram.v │ ├── debouncer.v │ ├── button_parser.v │ ├── z1top.xdc │ ├── z1top.v │ └── sine.bin ├── sim │ ├── fsm_tb.v │ ├── sq_wave_gen_tb.v │ ├── dac_tb.v │ ├── nco_tb.v │ └── sine.bin └── scripts │ └── nco.py ├── lab5 ├── Makefile ├── spec │ └── figs │ │ ├── pmod_a.jpg │ │ ├── uart_rx.png │ │ ├── uart_tx.png │ │ ├── 2_rv_beats.pdf │ │ ├── 2_rv_beats.png │ │ ├── flowchart.png │ │ ├── mem_packets.png │ │ ├── sink_source.png │ │ ├── uart_frame.png │ │ ├── backpressure.pdf │ │ ├── backpressure.png │ │ ├── Lab5_Block_Diagram.png │ │ ├── Lab6_Block_Diagram.pdf │ │ ├── Lab6_Block_Diagram.png │ │ ├── high_level_diagram.png │ │ ├── sync_fifo_diagram.png │ │ ├── sync_fifo_read_operation.png │ │ ├── sync_fifo_write_operation.png │ │ └── Lab6_Block_Diagram.xml ├── src │ ├── fifo.v │ ├── edge_detector.v │ ├── fixed_length_piano.v │ ├── synchronizer.v │ ├── uart_transmitter.v │ ├── memory.v │ ├── debouncer.v │ ├── button_parser.v │ ├── uart.v │ ├── mem_controller.v │ ├── z1top.xdc │ ├── uart_receiver.v │ ├── sine.bin │ ├── z1top.v │ └── piano_scale_rom.v └── sim │ ├── sine.bin │ ├── piano_system_tb.v │ ├── echo_tb.v │ ├── uart2uart_tb.v │ ├── simple_echo_tb.v │ ├── uart_transmitter_tb.v │ ├── system_tb.v │ ├── fifo_tb.v │ └── mem_controller_tb.v ├── scripts ├── synth.tcl ├── elaborate.tcl ├── impl.tcl ├── program.tcl ├── rom_generator ├── audio_from_sim ├── piano ├── piano_scale_generator ├── program_2021.tcl └── musicxml_parser.py ├── README.md └── Makefrag /lab1/sim/dummy_sim.v: -------------------------------------------------------------------------------- 1 | //dummy 2 | -------------------------------------------------------------------------------- /lab1/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefrag 2 | -------------------------------------------------------------------------------- /lab2/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefrag 2 | -------------------------------------------------------------------------------- /lab3/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefrag 2 | -------------------------------------------------------------------------------- /lab4/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefrag 2 | -------------------------------------------------------------------------------- /lab5/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefrag 2 | -------------------------------------------------------------------------------- /lab1/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab1/.DS_Store -------------------------------------------------------------------------------- /lab2/spec/figs/dve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab2/spec/figs/dve.png -------------------------------------------------------------------------------- /lab3/spec/figs/pwm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab3/spec/figs/pwm.pdf -------------------------------------------------------------------------------- /lab3/spec/figs/pwm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab3/spec/figs/pwm.png -------------------------------------------------------------------------------- /lab4/spec/figs/fsm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab4/spec/figs/fsm.png -------------------------------------------------------------------------------- /lab4/spec/figs/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab4/spec/figs/top.png -------------------------------------------------------------------------------- /lab5/spec/figs/pmod_a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/pmod_a.jpg -------------------------------------------------------------------------------- /lab2/spec/figs/dve_wave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab2/spec/figs/dve_wave.png -------------------------------------------------------------------------------- /lab3/spec/figs/bouncing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab3/spec/figs/bouncing.png -------------------------------------------------------------------------------- /lab5/spec/figs/uart_rx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/uart_rx.png -------------------------------------------------------------------------------- /lab5/spec/figs/uart_tx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/uart_tx.png -------------------------------------------------------------------------------- /lab1/spec/figs/x2go_setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab1/spec/figs/x2go_setup.png -------------------------------------------------------------------------------- /lab3/spec/figs/audio_out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab3/spec/figs/audio_out.png -------------------------------------------------------------------------------- /lab3/spec/figs/debouncer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab3/spec/figs/debouncer.png -------------------------------------------------------------------------------- /lab4/spec/figs/lab4figs.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab4/spec/figs/lab4figs.pptx -------------------------------------------------------------------------------- /lab5/spec/figs/2_rv_beats.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/2_rv_beats.pdf -------------------------------------------------------------------------------- /lab5/spec/figs/2_rv_beats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/2_rv_beats.png -------------------------------------------------------------------------------- /lab5/spec/figs/flowchart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/flowchart.png -------------------------------------------------------------------------------- /lab5/spec/figs/mem_packets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/mem_packets.png -------------------------------------------------------------------------------- /lab5/spec/figs/sink_source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/sink_source.png -------------------------------------------------------------------------------- /lab5/spec/figs/uart_frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/uart_frame.png -------------------------------------------------------------------------------- /lab3/spec/figs/metastability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab3/spec/figs/metastability.png -------------------------------------------------------------------------------- /lab3/spec/figs/synchronizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab3/spec/figs/synchronizer.png -------------------------------------------------------------------------------- /lab5/spec/figs/backpressure.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/backpressure.pdf -------------------------------------------------------------------------------- /lab5/spec/figs/backpressure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/backpressure.png -------------------------------------------------------------------------------- /lab1/spec/figs/vivado_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab1/spec/figs/vivado_options.png -------------------------------------------------------------------------------- /lab1/spec/figs/z1_top_annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab1/spec/figs/z1_top_annotated.png -------------------------------------------------------------------------------- /lab5/spec/figs/Lab5_Block_Diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/Lab5_Block_Diagram.png -------------------------------------------------------------------------------- /lab5/spec/figs/Lab6_Block_Diagram.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/Lab6_Block_Diagram.pdf -------------------------------------------------------------------------------- /lab5/spec/figs/Lab6_Block_Diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/Lab6_Block_Diagram.png -------------------------------------------------------------------------------- /lab5/spec/figs/high_level_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/high_level_diagram.png -------------------------------------------------------------------------------- /lab5/spec/figs/sync_fifo_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/sync_fifo_diagram.png -------------------------------------------------------------------------------- /lab1/spec/figs/z1_bottom_annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab1/spec/figs/z1_bottom_annotated.png -------------------------------------------------------------------------------- /lab5/spec/figs/sync_fifo_read_operation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/sync_fifo_read_operation.png -------------------------------------------------------------------------------- /lab5/spec/figs/sync_fifo_write_operation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_labs_fa22/HEAD/lab5/spec/figs/sync_fifo_write_operation.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lab5/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lab3/src/counter.v: -------------------------------------------------------------------------------- 1 | module counter #( 2 | parameter CYCLES_PER_SECOND = 125_000_000 3 | )( 4 | input clk, 5 | input [3:0] buttons, 6 | output [3:0] leds 7 | ); 8 | reg [3:0] counter = 0; 9 | assign leds = counter; 10 | 11 | always @(posedge clk) begin 12 | if (buttons[0]) 13 | counter <= counter + 4'd1; 14 | else if (buttons[1]) 15 | counter <= counter - 4'd1; 16 | else if (buttons[3]) 17 | counter <= 4'd0; 18 | else 19 | counter <= counter; 20 | end 21 | endmodule 22 | 23 | -------------------------------------------------------------------------------- /lab5/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/elaborate.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 | # Only elaborate RTL (don't synthesize to netlist) 14 | synth_design -top ${TOP} -part ${FPGA_PART} -rtl 15 | 16 | # write_checkpoint doesn't work: 17 | # Vivado% write_checkpoint -force z1top_post_elab.dcp 18 | # ERROR: [Common 17-69] Command failed: Checkpoints are not supported for RTL designs 19 | 20 | # Open the schematic visualization 21 | start_gui 22 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/impl.tcl: -------------------------------------------------------------------------------- 1 | source ../target.tcl 2 | 3 | open_checkpoint ${ABS_TOP}/build/synth/${TOP}.dcp 4 | 5 | if {[string trim ${CONSTRAINTS}] ne ""} { 6 | read_xdc ${CONSTRAINTS} 7 | } 8 | 9 | opt_design 10 | place_design 11 | write_checkpoint -force ${TOP}_placed.dcp 12 | report_utilization -file post_place_utilization.rpt 13 | phys_opt_design 14 | route_design 15 | 16 | write_checkpoint -force ${TOP}_routed.dcp 17 | write_verilog -force post_route.v 18 | write_xdc -force post_route.xdc 19 | report_drc -file post_route_drc.rpt 20 | report_timing_summary -warn_on_violation -file post_route_timing_summary.rpt 21 | 22 | write_bitstream -force ${TOP}.bit 23 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /lab5/src/memory.v: -------------------------------------------------------------------------------- 1 | module memory #( 2 | parameter MEM_WIDTH = 32, 3 | parameter DEPTH = 128, 4 | parameter NUM_BYTES_PER_WORD = MEM_WIDTH/8, 5 | parameter MEM_ADDR_WIDTH = $clog2(DEPTH) 6 | ) ( 7 | input clk, 8 | input en, 9 | input [NUM_BYTES_PER_WORD-1:0] we, 10 | input [MEM_ADDR_WIDTH-1:0] addr, 11 | input [MEM_WIDTH-1:0] din, 12 | output reg [MEM_WIDTH-1:0] dout 13 | ); 14 | // No change needs to be made for this file 15 | // See page 133 of the Vivado Synthesis Guide for the template 16 | // https://www.xilinx.com/support/documentation/sw_manuals/xilinx2016_4/ug901-vivado-synthesis.pdf 17 | 18 | reg [MEM_WIDTH-1:0] mem [DEPTH-1:0]; 19 | 20 | integer i; 21 | always @(posedge clk) begin 22 | if (en) begin 23 | for(i=0; i < NUM_BYTES_PER_WORD; i=i+1) begin 24 | if (we[i]) begin 25 | mem[addr][i*8 +: 8] <= din[i*8 +: 8]; 26 | end 27 | end 28 | dout <= mem[addr]; 29 | end 30 | end 31 | 32 | endmodule 33 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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(' 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 | -------------------------------------------------------------------------------- /lab5/src/mem_controller.v: -------------------------------------------------------------------------------- 1 | module mem_controller #( 2 | parameter FIFO_WIDTH = 8 3 | ) ( 4 | input clk, 5 | input rst, 6 | input rx_fifo_empty, 7 | input tx_fifo_full, 8 | input [FIFO_WIDTH-1:0] din, 9 | 10 | output rx_fifo_rd_en, 11 | output tx_fifo_wr_en, 12 | output [FIFO_WIDTH-1:0] dout, 13 | output [5:0] state_leds 14 | ); 15 | 16 | localparam MEM_WIDTH = 8; /* Width of each mem entry (word) */ 17 | localparam MEM_DEPTH = 256; /* Number of entries */ 18 | localparam NUM_BYTES_PER_WORD = MEM_WIDTH/8; 19 | localparam MEM_ADDR_WIDTH = $clog2(MEM_DEPTH); 20 | 21 | reg [NUM_BYTES_PER_WORD-1:0] mem_we = 0; 22 | reg [MEM_ADDR_WIDTH-1:0] mem_addr; 23 | reg [MEM_WIDTH-1:0] mem_din; 24 | wire [MEM_WIDTH-1:0] mem_dout; 25 | 26 | memory #( 27 | .MEM_WIDTH(MEM_WIDTH), 28 | .DEPTH(MEM_DEPTH) 29 | ) mem( 30 | .clk(clk), 31 | .en(1'b1), 32 | .we(mem_we), 33 | .addr(mem_addr), 34 | .din(mem_din), 35 | .dout(mem_dout) 36 | ); 37 | 38 | localparam 39 | IDLE = 3'd0, 40 | READ_CMD = 3'd1, 41 | READ_ADDR = 3'd2, 42 | READ_DATA = 3'd3, 43 | READ_MEM_VAL = 3'd4, 44 | ECHO_VAL = 3'd5, 45 | WRITE_MEM_VAL = 3'd6; 46 | 47 | reg [2:0] curr_state; 48 | reg [2:0] next_state; 49 | 50 | always @(posedge clk) begin 51 | 52 | /* state reg update */ 53 | 54 | end 55 | 56 | reg [2:0] pkt_rd_cnt; 57 | reg [MEM_WIDTH-1:0] cmd; 58 | reg [MEM_WIDTH-1:0] addr; 59 | reg [MEM_WIDTH-1:0] data; 60 | reg handshake; 61 | 62 | 63 | always @(*) begin 64 | 65 | /* initial values to avoid latch synthesis */ 66 | 67 | case (curr_state) 68 | 69 | /* next state logic */ 70 | 71 | endcase 72 | 73 | end 74 | 75 | always @(*) begin 76 | 77 | /* initial values to avoid latch synthesis */ 78 | 79 | case (curr_state) 80 | 81 | /* output and mem signal logic */ 82 | 83 | endcase 84 | 85 | end 86 | 87 | 88 | always @(posedge clk) begin 89 | 90 | /* byte reading and packet counting */ 91 | 92 | end 93 | 94 | /* TODO: MODIFY THIS */ 95 | assign state_leds = 'd0; 96 | 97 | /* TODO: MODIFY/REMOVE THIS */ 98 | assign rx_fifo_rd_en = 'd0; 99 | assign tx_fifo_wr_en = 'd0; 100 | assign dout = 'd0; 101 | 102 | endmodule 103 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | #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 | repeat (4) begin 51 | @(posedge clk); #1; 52 | assert(pwm == 1) else $error("pwm should be 1 on first half of code = 3"); 53 | end 54 | repeat (4) begin 55 | @(posedge clk); #1; 56 | assert(pwm == 0) else $error("pwm should be 0 on first half of code = 3"); 57 | end 58 | end 59 | 60 | repeat (2) begin 61 | code = 2; 62 | repeat (3) begin 63 | @(posedge clk); #1; 64 | assert(pwm == 1) else $error("pwm should be 1 on first half of code = 3"); 65 | end 66 | repeat (5) begin 67 | @(posedge clk); #1; 68 | assert(pwm == 0) else $error("pwm should be 0 on first half of code = 3"); 69 | end 70 | end 71 | end 72 | // Thread to check next_sample 73 | begin 74 | repeat (6) begin 75 | assert(next_sample == 0) else $error("next_sample should start at 0"); 76 | repeat (7) @(posedge clk); #1; 77 | assert(next_sample == 1) else $error("next_sample should become 1 after 7 cycles"); 78 | @(posedge clk); #1; 79 | assert(next_sample == 0) else $error("next_sample should go back to 0 on the 8th cycle"); 80 | end 81 | end 82 | join 83 | 84 | $display("Test finished"); 85 | 86 | `ifndef IVERILOG 87 | $vcdplusoff; 88 | `endif 89 | $finish(); 90 | end 91 | endmodule 92 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lab5/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== -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /lab5/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 | -------------------------------------------------------------------------------- /lab5/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 | -------------------------------------------------------------------------------- /scripts/musicxml_parser.py: -------------------------------------------------------------------------------- 1 | import wave 2 | import random 3 | import struct 4 | import sys 5 | import zipfile 6 | from xml.dom import minidom 7 | import os 8 | import glob 9 | import shutil 10 | 11 | step_to_int = { 12 | 'A': 1, 13 | 'B': 3, 14 | 'C': 4, 15 | 'D': 6, 16 | 'E': 8, 17 | 'F': 9, 18 | 'G': 11 19 | } 20 | 21 | # Remove the temp directory from previous runs 22 | if (os.path.isdir('temp/')): 23 | shutil.rmtree('temp/') 24 | 25 | # Fetch the filepath to the compressed MusicXML file (.mxl) 26 | musicxml_filepath = sys.argv[1] 27 | 28 | # Fetch the filepath to the generated memory contents file 29 | memory_contents_filepath = sys.argv[2] 30 | 31 | # Unzip the compressed file to the temp directory 32 | zip_ref = zipfile.ZipFile(musicxml_filepath, 'r') 33 | zip_ref.extractall('temp/') 34 | zip_ref.close() 35 | 36 | # Fetch and parse the XML file in the temp directory 37 | xml_filepath = glob.glob("temp/*.xml") 38 | #print(xml_filepath) 39 | xmldoc = minidom.parse(xml_filepath[0]) 40 | 41 | # Print the XML tree for debugging 42 | #print(xmldoc.toprettyxml()) 43 | 44 | # For the first part in the sheet music 45 | parts = xmldoc.getElementsByTagName('part')[0] 46 | 47 | notes = [] 48 | 49 | # Loop through every measure and pull each note 50 | for measure in parts.getElementsByTagName('measure'): 51 | print("measure %s" % (measure.getAttribute('number'))) 52 | for note in measure.getElementsByTagName('note'): 53 | rest_check = note.getElementsByTagName('rest') 54 | if (len(rest_check) > 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 | -------------------------------------------------------------------------------- /lab5/sim/piano_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 piano_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; /* Set this correctly for piano mode! */ 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | 22 | wire [2:0] buttons_pressed; 23 | wire reset; 24 | wire [1:0] switches_sync; 25 | 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 | wire [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 | //---------------------- LED OUTPUT --------------------- 47 | 48 | wire [5:0] fl_leds; 49 | wire [5:0] mem_state_leds; 50 | 51 | assign LEDS = switches_sync[0] ? fl_leds : mem_state_leds; 52 | 53 | //------------------------- UART --------------------------- 54 | // This UART is on the FPGA and communicates with your desktop 55 | // using the FPGA_SERIAL_TX, and FPGA_SERIAL_RX signals. The ready/valid 56 | // interface for this UART is used on the FPGA design. 57 | uart # (.CLOCK_FREQ(CLOCK_FREQ),.BAUD_RATE(BAUD_RATE)) 58 | on_chip_uart ( 59 | .clk(CLK_125MHZ_FPGA), 60 | .reset(reset), 61 | .data_in(data_in), 62 | .data_in_valid(data_in_valid), 63 | .data_in_ready(data_in_ready), 64 | .data_out(data_out), 65 | .data_out_valid(data_out_valid), 66 | .data_out_ready(data_out_ready), 67 | .serial_in(FPGA_SERIAL_RX), 68 | .serial_out(FPGA_SERIAL_TX) 69 | ); 70 | //------------------------- RX FIFO --------------------------- 71 | wire rx_fifo_full; 72 | assign data_out_ready = ~rx_fifo_full; 73 | wire [7:0] rx_dout; 74 | wire rx_fifo_empty; 75 | wire rx_rd_en, fl_rx_rd_en, mem_rx_rd_en; 76 | 77 | assign rx_rd_en = switches_sync[0] ? fl_rx_rd_en : mem_rx_rd_en; 78 | 79 | fifo #(.WIDTH(8), .DEPTH(8)) 80 | rx_fifo ( 81 | .clk(CLK_125MHZ_FPGA), .rst(reset), 82 | .wr_en(data_out_valid && ~rx_fifo_full), 83 | .din(data_out), 84 | .full(rx_fifo_full), 85 | .rd_en(rx_rd_en), 86 | .dout(rx_dout), 87 | .empty(rx_fifo_empty) 88 | ); 89 | 90 | 91 | //------------------------- TX FIFO --------------------------- 92 | wire [7:0] tx_din, fl_din, mem_din; 93 | assign tx_din = switches_sync[0] ? fl_din : mem_din; 94 | 95 | wire tx_fifo_full, tx_wr_en, fl_tx_wr_en, mem_tx_wr_en; 96 | assign tx_wr_en = switches_sync[0] ? fl_tx_wr_en : mem_tx_wr_en; 97 | 98 | wire tx_fifo_empty; 99 | reg tx_fifo_empty_delayed; 100 | assign data_in_valid = ~tx_fifo_empty_delayed; 101 | always @(posedge CLK_125MHZ_FPGA) begin 102 | tx_fifo_empty_delayed <= tx_fifo_empty; 103 | end 104 | 105 | fifo #(.WIDTH(8), .DEPTH(8)) 106 | tx_fifo ( 107 | .clk(CLK_125MHZ_FPGA), .rst(reset), 108 | .wr_en(tx_wr_en), 109 | .din(tx_din), 110 | .full(tx_fifo_full), 111 | .rd_en(data_in_ready && ~tx_fifo_empty), 112 | .dout(data_in), 113 | .empty(tx_fifo_empty) 114 | ); 115 | 116 | 117 | 118 | //------------------------- MEM CONTROLLER --------------------------- 119 | mem_controller #(.FIFO_WIDTH(8)) 120 | mem_ctrl ( 121 | .clk(CLK_125MHZ_FPGA),.rst(reset), 122 | .rx_fifo_empty(rx_fifo_empty), 123 | .tx_fifo_full(tx_fifo_full), 124 | .din(rx_dout), 125 | .rx_fifo_rd_en(mem_rx_rd_en), 126 | .tx_fifo_wr_en(mem_tx_wr_en), 127 | .dout(mem_din), 128 | .state_leds(mem_state_leds) 129 | ); 130 | 131 | /* 132 | //---------------------- Audio Code Below (Extra Credit) --------------------- 133 | 134 | wire [9:0] code; 135 | wire [23:0] fcw, fl_fcw; 136 | assign fcw = switches_sync[1] ? fl_fcw : 24'b0; 137 | wire next_sample; 138 | 139 | dac dac ( 140 | .clk(CLK_125MHZ_FPGA), 141 | .rst(reset), 142 | .code(code), 143 | .next_sample(next_sample), 144 | .pwm(AUD_PWM) 145 | ); 146 | 147 | nco nco ( 148 | .clk(CLK_125MHZ_FPGA), 149 | .rst(reset), 150 | .fcw(fcw), 151 | .next_sample(next_sample), 152 | .code(code) 153 | ); 154 | 155 | fixed_length_piano #( 156 | .CYCLES_PER_SECOND(CYCLES_PER_SECOND)) 157 | fl_piano ( 158 | .clk(CLK_125MHZ_FPGA),.rst(reset), 159 | .buttons(buttons_pressed), 160 | .leds(fl_leds), 161 | .ua_tx_din(fl_din), 162 | .ua_tx_wr_en(fl_tx_wr_en), 163 | .ua_tx_full(tx_fifo_full), 164 | .ua_rx_dout(rx_dout), 165 | .ua_rx_empty(rx_fifo_empty), 166 | .ua_rx_rd_en(fl_rx_rd_en), 167 | .fcw(fl_fcw) 168 | ); 169 | 170 | assign AUD_SD = switches_sync[1]; // Enable the audio output 171 | 172 | */ 173 | 174 | endmodule 175 | -------------------------------------------------------------------------------- /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/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/sim/system_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ps 2 | 3 | `define CLK_PERIOD 8 4 | `define B_SAMPLE_CNT_MAX 5 5 | `define B_PULSE_CNT_MAX 5 6 | 7 | `define CLOCK_FREQ 125_000_000 8 | `define BAUD_RATE 25_000_000 9 | `define CYCLES_PER_CHAR ((`CLOCK_FREQ / `BAUD_RATE) * 10) // Number of cycles to send one packet using the UART 10 | `define CYCLES_PER_SECOND (`CYCLES_PER_CHAR * 6) 11 | 12 | module system_tb(); 13 | 14 | reg clk = 0; 15 | reg rst; 16 | reg [2:0] buttons; 17 | reg [1:0] switches; 18 | reg [7:0] off_chip_data_in; 19 | reg off_chip_data_in_valid; 20 | reg off_chip_data_out_ready; 21 | wire off_chip_data_out_valid; 22 | wire off_chip_data_in_ready; 23 | wire [7:0] off_chip_data_out; 24 | 25 | wire FPGA_SERIAL_RX; 26 | wire FPGA_SERIAL_TX; 27 | wire [5:0] leds; 28 | 29 | localparam integer SYMBOL_EDGE_TIME = `CLOCK_FREQ / `BAUD_RATE; 30 | localparam CHAR0 = 8'h41; // ~ 'A' 31 | localparam MEM_DEPTH = 256; 32 | localparam FIFO_DEPTH = 8; 33 | localparam NUM_CHARS = 26; 34 | 35 | // Generate system clock 36 | always #(`CLK_PERIOD/2) clk <= ~clk; 37 | 38 | reg [7:0] tests_failed = 0; 39 | 40 | z1top #( 41 | .B_SAMPLE_CNT_MAX(`B_SAMPLE_CNT_MAX), 42 | .B_PULSE_CNT_MAX(`B_PULSE_CNT_MAX), 43 | .CLOCK_FREQ(`CLOCK_FREQ), 44 | .BAUD_RATE(`BAUD_RATE), 45 | .CYCLES_PER_SECOND(`CYCLES_PER_SECOND) 46 | ) top ( 47 | .CLK_125MHZ_FPGA(clk), 48 | .BUTTONS({buttons, rst}), 49 | .SWITCHES(switches), 50 | .LEDS(leds), 51 | .AUD_PWM(), 52 | .FPGA_SERIAL_RX(FPGA_SERIAL_RX), 53 | .FPGA_SERIAL_TX(FPGA_SERIAL_TX) 54 | ); 55 | 56 | /* An off-chip UART here that uses the RX and TX lines 57 | emulating the host (computer) */ 58 | uart #( 59 | .BAUD_RATE(`BAUD_RATE), 60 | .CLOCK_FREQ(`CLOCK_FREQ) 61 | ) off_chip_uart ( 62 | .clk(clk), 63 | .reset(rst), 64 | .data_in(off_chip_data_in), 65 | .data_in_valid(off_chip_data_in_valid), 66 | .data_in_ready(off_chip_data_in_ready), 67 | .data_out(off_chip_data_out), 68 | .data_out_valid(off_chip_data_out_valid), 69 | .data_out_ready(off_chip_data_out_ready), 70 | .serial_in(FPGA_SERIAL_TX), 71 | .serial_out(FPGA_SERIAL_RX) 72 | ); 73 | 74 | /* Define a task that sends data to z1_top via the off_chip_uart */ 75 | task off_chip_uart_send; 76 | input [7:0] data; 77 | begin 78 | while (!off_chip_data_in_ready) begin 79 | @(posedge clk); 80 | end 81 | #1; 82 | $display("Sending byte: %d.", data); 83 | off_chip_data_in_valid = 'b1; 84 | off_chip_data_in = data; 85 | @(posedge clk); 86 | #1; 87 | off_chip_data_in_valid = 'b0; 88 | end 89 | endtask 90 | 91 | /* Define a task that checks data received by the off_chip_uart from z1_top */ 92 | task off_chip_uart_receive; 93 | input [7:0] data; 94 | begin 95 | while (!off_chip_data_out_valid) begin 96 | @(posedge clk); 97 | end 98 | #1; 99 | off_chip_data_out_ready = 1'b0; 100 | assert(off_chip_data_out == data) $display("PASSED! Expected : %d Actual %d", data, off_chip_data_out); else begin 101 | $error("FAILED! Expected : %d Actual %d, TX_FIFO_out is %d", data, off_chip_data_out, top.data_in); 102 | tests_failed += 1; 103 | end 104 | @(posedge clk); 105 | off_chip_data_out_ready = 1'b1; // so the off_chip_rx_fifo will clear the "has byte" again 106 | end 107 | endtask 108 | 109 | 110 | /* Define a wrapper for write */ 111 | task write_packet; 112 | input [7:0] addr; 113 | input [7:0] data; 114 | input bool_delay; 115 | begin 116 | off_chip_uart_send(8'd49); 117 | 118 | if (bool_delay) repeat (2) @(posedge clk); 119 | 120 | off_chip_uart_send(addr); 121 | 122 | if (bool_delay) repeat (1) @(posedge clk); 123 | 124 | off_chip_uart_send(data); 125 | 126 | end 127 | endtask 128 | 129 | /* Define a wrapper for read */ 130 | task read_packet; 131 | input [7:0] addr; 132 | input [7:0] expected_data; 133 | input bool_delay; 134 | begin 135 | 136 | off_chip_uart_send(8'd48); 137 | 138 | if(bool_delay) repeat (2) @(posedge clk); 139 | off_chip_uart_send(addr); 140 | 141 | if(bool_delay) repeat (1) @(posedge clk); 142 | 143 | wait(top.tx_fifo.rd_en == 1'b1); 144 | @(posedge clk); 145 | 146 | off_chip_uart_receive(expected_data); 147 | 148 | end 149 | endtask 150 | 151 | initial begin 152 | 153 | `ifndef IVERILOG 154 | $vcdpluson; 155 | $vcdplusmemon; 156 | `endif 157 | `ifdef IVERILOG 158 | $dumpfile("system_tb.fst"); 159 | $dumpvars(0, system_tb); 160 | for(z = 0; z < MEM_DEPTH; z = z + 1) begin 161 | // to show each entry of the 2D reg in your mem on the waveform 162 | $dumpvars(0, top.mem_ctrl.mem.mem[z]); 163 | end 164 | for(z = 0; z < FIFO_DEPTH; z = z + 1) begin 165 | // to show each entry of the 2D regs in your FIFOs on the waveform 166 | // Uncomment the following lines and replace "data" with the name of your 2D reg 167 | // $dumpvars(0, top.rx_fifo.data[z]); 168 | // $dumpvars(0, top.tx_fifo.data[z]); 169 | end 170 | `endif 171 | off_chip_data_in = 8'd0; 172 | off_chip_data_in_valid = 1'b0; 173 | off_chip_data_out_ready = 1'b1; 174 | buttons = 0; 175 | switches = 0; 176 | 177 | /* Simulate pushing the reset button and holding it for a while */ 178 | rst = 1'b0; 179 | repeat (5) @(posedge clk); #1; 180 | rst = 1'b1; 181 | repeat (40) @(posedge clk); #1; 182 | rst = 1'b0; 183 | 184 | // simple W-R test 185 | $display("------- Running simple test -------"); 186 | assert(FPGA_SERIAL_TX == 1'b1); 187 | assert(FPGA_SERIAL_RX == 1'b1); 188 | $display("------- Write a Byte -------"); 189 | write_packet(8'd11, CHAR0,1'b0); 190 | repeat(`CYCLES_PER_CHAR * 5) @(posedge clk); 191 | $display("------- Read a Byte -------"); 192 | read_packet(8'd11, CHAR0,1'b0); 193 | 194 | repeat(10) @(posedge clk); 195 | 196 | // consecutive W, then R 197 | $display("------- Running harder test -------"); 198 | assert(FPGA_SERIAL_TX == 1'b1); 199 | assert(FPGA_SERIAL_RX == 1'b1); 200 | for(integer i = 0; i < NUM_CHARS; i += 1) begin 201 | write_packet(8'd0+i, CHAR0+i,1'b0); 202 | end 203 | for(integer i = NUM_CHARS-1; i >= 0; i -= 1) begin 204 | read_packet(8'd0+i, CHAR0+i,1'b0); 205 | end 206 | 207 | $display("All tests done!"); 208 | 209 | if (tests_failed == 0) 210 | $display("\nAll tests PASSED!\n"); 211 | else 212 | $display("\n%d tests FAILED.\n", tests_failed); 213 | 214 | `ifndef IVERILOG 215 | $vcdplusoff; 216 | $vcdplusmemoff; 217 | `endif 218 | $finish(); 219 | 220 | end 221 | 222 | // initial begin 223 | // fork 224 | // begin while(1)begin 225 | // wait(top.mem_ctrl.rx_fifo_rd_en == 1'b0); 226 | // wait(top.mem_ctrl.rx_fifo_rd_en == 1'b1); 227 | // @ (posedge clk); 228 | // @ (posedge clk); 229 | // //$display("RX FIFO out is %d, cmd is %d, pkt_rd_count is %d", top.mem_ctrl.din, top.mem_ctrl.cmd, top.mem_ctrl.pkt_rd_cnt); 230 | // //wait(top.mem_ctrl.curr_state == 3'd2 || top.mem_ctrl.curr_state == 3'd3); 231 | // end 232 | // end 233 | // begin 234 | 235 | // while(1)begin 236 | // wait(top.mem_ctrl.pkt_rd_cnt == 3); 237 | // @ (posedge clk); 238 | // @ (posedge clk); 239 | // //$display("RX FIFO out is %d, pkt_rd_count is %d", top.mem_ctrl.din, top.mem_ctrl.pkt_rd_cnt); 240 | // //wait(top.mem_ctrl.curr_state == 3'd2 || top.mem_ctrl.curr_state == 3'd3); 241 | // wait(top.mem_ctrl.pkt_rd_cnt == 0); 242 | // end 243 | 244 | // end 245 | // join 246 | // end 247 | 248 | initial begin 249 | repeat (`CYCLES_PER_CHAR * 500) @(posedge clk); 250 | $error("Timing out"); 251 | $fatal(); 252 | end 253 | endmodule 254 | 255 | 256 | 257 | 258 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lab5/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 | -------------------------------------------------------------------------------- /lab5/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 -------------------------------------------------------------------------------- /lab5/sim/mem_controller_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | `define CLK_PERIOD 8 4 | 5 | /* mem_controller_tb v2 */ 6 | 7 | module mem_controller_tb(); 8 | 9 | localparam FIFO_WIDTH = 8; 10 | localparam FIFO_DEPTH = 8; 11 | localparam MEM_DEPTH = 256; 12 | localparam NUM_WRITES = 10; 13 | localparam NUM_READS = 10; 14 | localparam CHAR0 = 8'd65; /* ASCII 'A' */ 15 | 16 | reg clk = 0; 17 | reg rst = 0; 18 | 19 | always #(`CLK_PERIOD/2) clk <= ~clk; 20 | 21 | 22 | /* Mem <-> RX_FIFO and TX_FIFO signals */ 23 | wire mem_rx_empty; 24 | wire mem_tx_full; 25 | wire mem_rx_rd_en; 26 | wire mem_tx_wr_en; 27 | wire [FIFO_WIDTH-1:0] rx_dout; 28 | wire [FIFO_WIDTH-1:0] tx_din; 29 | wire [5:0] LEDS; 30 | 31 | /* TB <-> RX_FIFO signals */ 32 | // Enqueue signals (Write to RX_FIFO) 33 | reg tb_rx_wr_en = 0; 34 | reg [FIFO_WIDTH-1:0] tb_rx_din; 35 | wire tb_rx_full; 36 | 37 | // Dequeue signals (Read from TX_FIFO) 38 | wire tb_tx_empty; 39 | wire [FIFO_WIDTH-1:0] tb_tx_dout; 40 | reg tb_tx_rd_en = 0; 41 | 42 | fifo #( 43 | .WIDTH(FIFO_WIDTH), 44 | .DEPTH(FIFO_DEPTH) 45 | ) rx_fifo ( 46 | .clk(clk), 47 | .rst(rst), 48 | 49 | .wr_en(tb_rx_wr_en), // input 50 | .din(tb_rx_din), // input 51 | .full(tb_rx_full), // output 52 | 53 | .empty(mem_rx_empty), // output 54 | .dout(rx_dout), // output 55 | .rd_en(mem_rx_rd_en) // input 56 | ); 57 | 58 | fifo #( 59 | .WIDTH(FIFO_WIDTH), 60 | .DEPTH(FIFO_DEPTH) 61 | ) tx_fifo ( 62 | .clk(clk), 63 | .rst(rst), 64 | 65 | .wr_en(mem_tx_wr_en), // input 66 | .din(tx_din), // input 67 | .full(mem_tx_full), // output 68 | 69 | .empty(tb_tx_empty), // output 70 | .dout(tb_tx_dout), // output 71 | .rd_en(tb_tx_rd_en) // input 72 | ); 73 | 74 | mem_controller #(.FIFO_WIDTH(FIFO_WIDTH)) 75 | mem_ctrl ( 76 | .clk(clk),.rst(rst), 77 | .rx_fifo_empty(mem_rx_empty), 78 | .tx_fifo_full(mem_tx_full), 79 | .din(rx_dout), 80 | .rx_fifo_rd_en(mem_rx_rd_en), 81 | .tx_fifo_wr_en(mem_tx_wr_en), 82 | .dout(tx_din), 83 | .state_leds(LEDS) 84 | ); 85 | 86 | /* Test Vectors */ 87 | /* WRITE (8'd49, 8'd, 8'd) in first to last byte order */ 88 | reg [23:0] test_write [NUM_WRITES-1 : 0]; 89 | /* READ (8'd48, 8'd) in first to last byte order */ 90 | reg [15:0] test_read [NUM_READS-1 : 0]; 91 | reg [7:0] test_read_vals [NUM_READS-1: 0]; 92 | reg [7:0] tests_failed = 0; 93 | 94 | reg verified_write = 0; 95 | 96 | // This task will push some data to the RX_FIFO through the write interface 97 | task write_to_rx_fifo; 98 | input [FIFO_WIDTH-1:0] write_data; 99 | begin 100 | #1; 101 | 102 | // Wait until the fifo is not full 103 | wait(tb_rx_full == 0); 104 | 105 | // If we are already full, don't write 106 | if (tb_rx_full) begin 107 | tb_rx_wr_en = 1'b0; 108 | end 109 | // Else write 110 | else begin 111 | tb_rx_wr_en = 1'b1; 112 | end 113 | 114 | // Write should be performed when enq_ready and enq_valid are HIGH 115 | tb_rx_din = write_data; 116 | 117 | // Wait for the clock edge to perform the write 118 | @(posedge clk); #1; 119 | 120 | // Deassert write 121 | tb_rx_wr_en = 1'b0; 122 | end 123 | endtask 124 | 125 | // This task will read some data from the TX_FIFO through the read interface 126 | task read_from_tx_fifo; 127 | output [FIFO_WIDTH-1:0] rd_data; 128 | begin 129 | #1; 130 | 131 | // Wait until the fifo is not empty 132 | wait(tb_tx_empty == 0); 133 | 134 | if (tb_tx_empty) begin 135 | tb_tx_rd_en = 1'b0; 136 | end 137 | else begin 138 | tb_tx_rd_en = 1'b1; 139 | end 140 | 141 | // Deassert read 142 | @(posedge clk); #1; 143 | 144 | rd_data = tb_tx_dout; 145 | tb_tx_rd_en = 1'b0; 146 | end 147 | endtask 148 | 149 | 150 | task send_n_writes; 151 | input [7:0] n; 152 | begin 153 | 154 | for (integer w = 0; w < n; w += 1) begin 155 | 156 | write_to_rx_fifo(test_write[w][7:0]); /* command */ 157 | write_to_rx_fifo(test_write[w][15:8]); /* addr */ 158 | write_to_rx_fifo(test_write[w][23:16]); /* data */ 159 | 160 | wait (verified_write == 1); 161 | 162 | end 163 | 164 | end 165 | endtask 166 | 167 | reg [7:0] verify_addr; 168 | reg [7:0] verify_data; 169 | 170 | task verify_n_writes; 171 | input [7:0] n; 172 | begin 173 | for (integer w = 0; w < n; w += 1) begin 174 | 175 | verified_write = 0; 176 | 177 | verify_addr = test_write[w][15:8]; 178 | verify_data = test_write[w][23:16]; 179 | 180 | // wait (tb_rx_dout == 8'd49); 181 | 182 | // wait (~rx_fifo_empty && mem_rx_rd_en) begin 183 | // @(posedge clk); 184 | // #1; 185 | // verify_addr = rx_dout; 186 | // end 187 | 188 | // wait (~rx_fifo_empty && mem_rx_rd_en) begin 189 | // @(posedge clk); 190 | // #1; 191 | // verify_data = rx_dout; 192 | // end 193 | 194 | repeat (10) @(posedge clk); 195 | assert (mem_ctrl.mem.mem[verify_addr] == verify_data) $display("PASSED! Expected : %d Actual %d", verify_data, mem_ctrl.mem.mem[verify_addr]); else $error("FAILED! Expected : %d Actual %d", verify_data, mem_ctrl.mem.mem[verify_addr]); 196 | 197 | verified_write = 1; 198 | #1; 199 | 200 | end 201 | end 202 | endtask 203 | 204 | reg verified_read = 0; 205 | 206 | task send_n_reads; 207 | input [7:0] n; 208 | begin 209 | 210 | for (integer w = 0; w < n; w += 1) begin 211 | 212 | write_to_rx_fifo(test_read[w][7:0]); /* command */ 213 | write_to_rx_fifo(test_read[w][15:8]); /* addr */ 214 | 215 | wait (verified_read == 1); 216 | 217 | end 218 | 219 | end 220 | endtask 221 | 222 | reg [FIFO_WIDTH-1 : 0] read_data; 223 | 224 | task verify_n_reads; 225 | input [7:0] n; 226 | 227 | begin 228 | for (integer w = 0; w < n; w += 1) begin 229 | 230 | verified_read = 0; 231 | 232 | read_from_tx_fifo(read_data); 233 | 234 | assert (read_data == test_read_vals[w]) $display("PASSED! Expected : %d Actual %d", test_read_vals[w], read_data); else begin 235 | $error("FAILED! Expected : %d Actual %d", test_read_vals[w], read_data); 236 | tests_failed += 1; 237 | end 238 | 239 | @(posedge clk); // Wait for the cycle to end 240 | verified_read = 1; 241 | #1; 242 | 243 | end 244 | end 245 | endtask 246 | 247 | 248 | integer i, z; 249 | initial begin: TB 250 | 251 | `ifndef IVERILOG 252 | $vcdpluson; 253 | $vcdplusmemon; 254 | `endif 255 | `ifdef IVERILOG 256 | $dumpfile("mem_controller_tb.fst"); 257 | $dumpvars(0, mem_controller_tb); 258 | for(z = 0; z < MEM_DEPTH; z = z + 1) begin 259 | // to show each entry of the 2D reg in your mem on the waveform 260 | $dumpvars(0, mem_ctrl.mem.mem[z]); 261 | end 262 | for(z = 0; z < FIFO_DEPTH; z = z + 1) begin 263 | // to show each entry of the 2D regs in your FIFOs on the waveform 264 | // Uncomment the following lines and replace "data" with the name of your 2D reg 265 | // $dumpvars(0, rx_fifo.data[z]); 266 | // $dumpvars(0, tx_fifo.data[z]); 267 | end 268 | `endif 269 | 270 | /* Initialize write sequence */ 271 | for (i = 0; i < NUM_WRITES; i += 1) begin 272 | test_write[i][7:0] = 8'd49; 273 | test_write[i][15:8] = 10 + i; 274 | test_write[i][23:16] = CHAR0 + i; 275 | 276 | test_read[i][7:0] = 8'd48; 277 | test_read[i][15:8] = test_write[i][15:8]; 278 | 279 | test_read_vals[i] = test_write[i][23:16]; 280 | end 281 | 282 | rst = 1'b1; 283 | repeat (5) @(posedge clk); 284 | rst = 1'b0; 285 | @(posedge clk); 286 | 287 | repeat (10) @(posedge clk); 288 | 289 | /* 1 write */ 290 | $display("Sending a write packet..."); 291 | write_to_rx_fifo(test_write[0][7:0]); 292 | write_to_rx_fifo(test_write[0][15:8]); 293 | write_to_rx_fifo(test_write[0][23:16]); 294 | 295 | repeat (10) @(posedge clk); 296 | 297 | /* 1 read */ 298 | $display("Sending a read packet..."); 299 | write_to_rx_fifo(test_read[0][7:0]); 300 | write_to_rx_fifo(test_read[0][15:8]); 301 | read_from_tx_fifo(read_data); 302 | 303 | repeat (10) @(posedge clk); 304 | 305 | /* Probe memory to test whether writes reach memory correctly */ 306 | $display("Running consecutive writing tests..."); 307 | fork 308 | send_n_writes(8); 309 | verify_n_writes(8); 310 | join 311 | 312 | @(posedge clk); 313 | 314 | /* Test read results */ 315 | $display("Running consecutive reading tests..."); 316 | fork 317 | send_n_reads(8); 318 | verify_n_reads(8); 319 | join 320 | 321 | repeat (10) @(posedge clk); 322 | 323 | $display("Running interruption tests..."); 324 | 325 | /* Interrupt a write command with rx_fifo_empty = 1 after cmd, then after addr */ 326 | 327 | write_to_rx_fifo(test_write[8][7:0]); 328 | 329 | repeat (5) @(posedge clk); 330 | 331 | write_to_rx_fifo(test_write[8][15:8]); 332 | 333 | repeat (5) @(posedge clk); 334 | 335 | write_to_rx_fifo(test_write[8][23:16]); 336 | 337 | repeat (10) @(posedge clk); 338 | 339 | /* Check write */ 340 | 341 | assert (mem_ctrl.mem.mem[test_write[8][15:8]] == test_write[8][23:16]) $display("PASSED! Expected : %d Actual %d", test_write[8][23:16], mem_ctrl.mem.mem[test_write[8][15:8]]); else begin 342 | $error("FAILED! Expected : %d Actual %d", test_write[8][23:16], mem_ctrl.mem.mem[test_write[8][15:8]]); 343 | tests_failed += 1; 344 | end 345 | 346 | repeat (10) @(posedge clk); 347 | 348 | /* Send a simple write */ 349 | 350 | write_to_rx_fifo(test_write[9][7:0]); 351 | write_to_rx_fifo(test_write[9][15:8]); 352 | write_to_rx_fifo(test_write[9][23:16]); 353 | 354 | repeat (5) @(posedge clk); 355 | 356 | /* Interrupt a read command by leaving tx_fifo_full = 1 for a while */ 357 | 358 | verified_read = 1; // skip verification for 9 reads 359 | 360 | /* Send 10 reads */ 361 | send_n_reads(10); 362 | 363 | verified_read = 0; 364 | 365 | /* TX_FIFO of DEPTH 8 should be full */ 366 | 367 | /* Drain FIFO */ 368 | 369 | for (integer t = 0; t < 10; t += 1) begin 370 | read_from_tx_fifo(read_data); 371 | end 372 | 373 | assert (read_data == test_read_vals[9]) $display("PASSED! Expected : %d Actual %d", test_read_vals[9], read_data); else begin 374 | $error("FAILED! Expected : %d Actual %d", test_read_vals[9], read_data); 375 | tests_failed += 1; 376 | end 377 | 378 | repeat (10) @(posedge clk); 379 | 380 | if (tests_failed == 0) 381 | $display("\nAll tests PASSED!\n"); 382 | else 383 | $display("\n%d tests FAILED.\n", tests_failed); 384 | 385 | repeat (50) @(posedge clk); 386 | 387 | 388 | `ifndef IVERILOG 389 | $vcdplusoff; 390 | $vcdplusmemoff; 391 | `endif 392 | $finish(); 393 | end 394 | 395 | initial begin 396 | repeat (75000) @(posedge clk); 397 | $error("Timing out"); 398 | $fatal(); 399 | end 400 | 401 | endmodule 402 | -------------------------------------------------------------------------------- /lab4/spec/spec.md: -------------------------------------------------------------------------------- 1 | # FPGA Lab 4: Tunable Wave Generator, NCO, FSMs, RAMs 2 |

3 | Prof. Sophia Shao 4 |

5 |

6 | TAs: (ordered by section) Yikuan Chen, Simon Guo, Jennifer Zhou, Paul Kwon, Ella Schwarz, Raghav Gupta 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 | 17 | ### Fetch Latest Lab Skeleton 18 | ```shell 19 | cd fpga_labs_fa22 20 | git pull origin master 21 | ``` 22 | 23 | ### Copy Sources From Previous Lab 24 | ```shell 25 | cp lab3/src/synchronizer.v lab3/src/debouncer.v lab3/src/edge_detector.v lab4/src 26 | ``` 27 | 28 | ### Reading 29 | Look through these documents if you haven't already. 30 | 31 | - [Verilog Primer Slides](https://inst.eecs.berkeley.edu/~eecs151/fa22/files/verilog/Verilog_Primer_Slides.pdf) - overview of the Verilog language 32 | - [FSM](https://inst.eecs.berkeley.edu/~eecs151/fa22/files/verilog/verilog_fsm.pdf) - Finite State Machines in Verilog 33 | 34 | ## Overview 35 | In this lab we will: 36 | 37 | - Extend the functionality of the square wave generator we built in lab3 38 | - Use the buttons to adjust the output wave frequency 39 | - Write a Numerically Controlled Oscillator (NCO) 40 | - Initialize a ROM with a binary file and use it as an LUT 41 | - Design a phase accumulator (PA) 42 | - Design an FSM 43 | - Use buttons to switch between states 44 | - Use the FSM to control the NCO using a RAM 45 | - Test the circuit on the FPGA 46 | 47 | ## Part 1: Tunable Square Wave Generator 48 | In lab 3, we built a simple square wave generator which can emit a fixed 440Hz square wave tone. We would like to add more functionality. 49 | 50 | ### Implementation 51 | Support 2 modes of frequency adjustment, which can be achieved by directly adjusting the period: 52 | - *Linear Period Adjustment*: linearly increase or decrease the period by the `STEP` parameter for every button press 53 | - *Exponential Period Adjustment*: double or halve the period of the square wave for every button press (*hint*: use bitshifts) 54 | 55 | Use the button inputs as follows: 56 | - `button[0]` to decrease the period (thereby increasing the square wave frequency) 57 | - `button[1]` to increase the period (thereby decreasing the square wave frequency) 58 | - `button[2]` to switch between the 2 modes of frequency adjustment (linear period step/exponential) 59 | 60 | Use `leds[0]` to display the frequency adjustment mode. The other `leds` can be set as you wish. 61 | 62 | Since we now have a working button parser, we will use an explicit reset signal (`rst`) to make sure our registers don't hold undefined values (`X`) during simulation, and to gain the ability to reset our circuits at runtime. 63 | When `rst` is high on a rising clock edge, you should reset any registers in your circuit and reset the square wave frequency to 440 Hz. 64 | 65 | **Manually copy your DAC** from `lab3/src/dac.v` to `lab4/src/dac.v`. **Use the new `rst` signal** to reset registers inside your DAC *instead of* using initial values. Example: 66 | ```verilog 67 | // Initial register value - Don't do this anymore 68 | reg [4:0] counter = 0; 69 | ``` 70 | 71 | ```verilog 72 | // Explicit reset - Do this 73 | reg [4:0] counter; 74 | always @(posedge clk) begin 75 | if (rst) counter <= 0; // counter value will be undefined before rst. This is what we want. 76 | else begin 77 | //...(code here)... 78 | end 79 | end 80 | ``` 81 | 82 | Use your solution from lab 3 to **implement the new square wave generator** in `src/sq_wave_gen.v`. 83 | You should support a square wave frequency range from 20 Hz to 10 kHz. (*hint*: calculate the corresponding period) 84 | 85 | ### Verification 86 | **Extend the testbench** in `sim/sq_wave_gen_tb.v` to verify the reset and frequency adjustment functionality of your `sq_wave_gen`. 87 | Make sure your RTL can handle overflow (what happens when you keep pressing the same button?) 88 | 89 | The testbench has 2 simulation threads 90 | - The first one pulls samples from the `sq_wave_gen` at random intervals 91 | - The second one is for you **to write by simulating button presses**. You should use the `num_samples_fetched` variable to advance time in the simulation. 92 | - *Note*: the sample rate is `125e6 / 1024 = 122 kHz` 93 | - *Example*: to wait for a quarter of a second, you can use the delay statement `@(num_samples_fetched == 30517)`. This is computed by `wait_time * sample_rate = 0.25 * (125e6 / 1024) = 30517` 94 | 95 | You can use the same script from lab 3 to convert the simulation output to an audio file. 96 | ```shell 97 | ../scripts/audio_from_sim sim/codes.txt 98 | play output.wav 99 | ``` 100 | 101 | ### FPGA 102 | Look at `src/z1top.v` to see how the new `sq_wave_gen` is connected. 103 | Use `SWITCHES[1]` to turn the audio output on/off, and keep `SWITCHES[0]` low to use the `sq_wave_gen` module to drive the DAC. 104 | 105 | Use `make impl` and `make program` to **put the circuit on the FPGA and test it**. 106 | 107 | ## Part 2: NCO 108 | The top level schematic for the rest of this lab is shown below: 109 | 110 |

111 | 112 |

113 | 114 | ### NCO Overview 115 | Now we can generate tunable square waves using `sq_wave_gen`, but 1) they sound harsh and 2) we want to create a more general wave generation circuit that has frequency control and supports arbitrary waveform types. 116 | 117 | Let's use a numerically controlled oscillator (NCO) to generate sine waves. 118 | Here's the math involved: 119 | 120 | A **continuous time** sine wave, with a frequency $f_{sig}$, can be written as: 121 | 122 | $$f(t) = sin(2 \pi f_{sig} t)$$ 123 | 124 | If this sine wave is sampled with sampling frequency $f_{samp}$ (= 125e6 / 1024 = 122 kHz in our case), the resulting stream of discrete time samples is: 125 | 126 | $$f[n] = sin \left(2 \pi f_{sig} \frac{n}{f_{samp}}\right)$$ 127 | 128 | We want to let our hardware output such stream of samples. One way to do this is to use a **lookup table (LUT)** and a **phase accumulator** (PA, just a register that can increment its value). 129 | 130 | Say we have a LUT that contains sampled points for one period of a sine wave with $2^N$ entries. The entries `i` (where $0 \leq i \leq 2^N - 1$) of this LUT are: 131 | 132 | $$LUT[i] = sin\left(i \frac{2\pi}{2^N}\right)$$ 133 | 134 | To find the index ***i*** of the LUT that stores the ***n-th sample***, we can equate the expressions inside $sin()$: 135 | 136 | $$i \frac{2 \pi}{2^N} = 2 \pi f_{sig} \frac{n}{f_{samp}}$$ 137 | 138 | $$i = \underbrace{\left(\frac{f_{sig}}{f_{samp}} 2^N \right)}_{\text{phase increment}} n$$ 139 | 140 | This means that to calculate sample `n+1` for a given $f_{sig}$, we should take the LUT index ***i*** that corresponds to sample `n` and increment the index by the **frequency control word (FCW)** (also called the **phase increment** in the equation above). 141 | 142 | To find the frequency step, $\Delta_{f,min}$ , of the NCO (a.k.a frequency resolution) we can look at how much of a change in $f_{sig}$ could cause the FCW, or phase increment, to increase by 1: 143 | 144 | $$\frac{f_{sig} + \Delta_{f,min}}{f_{samp}} 2^N = \frac{f_{sig}}{f_{samp}}2^N + 1$$ 145 | 146 | $$\Delta_{f,min} = \frac{f_{samp}}{2^N}$$ 147 | 148 | In the equation above, $2^N$ is the total number of frequencies we could represent using N bits. In this lab we will use `N=24`. Recall that in lab 3, our DAC has a frequency of `122kHz`, which means the frequency resolution is `0.007Hz`. We can have very precise frequency control using an NCO. 149 | 150 | However, a $2^{24}$ entry LUT is huge and wouldn't fit on the FPGA. So, we will keep the phase accumulator `N` (24-bits) wide, and only use the MSB `M` bits to index the sine wave LUT. This means the LUT only contains $2^M$ entries, where `M` can be chosen based on the tolerable phase error. **We will use `M = 8` in this lab.** 151 | 152 | ### NCO Implementation 153 | We’ve generated a file that contains the contents of the LUT for you in `src/sine.bin`. You can run the following command to re-generate it: 154 | ```shell 155 | python scripts/nco.py --sine-lut > sine.bin 156 | ``` 157 | 158 | We can use the file to initialize a ROM inside `src/nco.v`. Use `$readmemb()` to load a ROM with initial contents like this: 159 | ```verilog 160 | reg [9:0] sine_lut [0:255]; 161 | initial begin 162 | $readmemb("sine.bin", sine_lut); 163 | end 164 | ``` 165 | If you are running a simulation in GUI Vivado, you must add this file to sim sources. 166 | 167 | **Implement** the NCO in `src/nco.v`. Note that the PA uses the main clock and runs at 125MHz. 168 | When `next_sample` is high, you should output a new DAC code on `out` on the next rising clock edge, similar to the `sq_wave_gen`. 169 | You can assume that `fcw` can change only when `next_sample` isn't high. 170 | 171 | ### NCO Verification 172 | We have provided a testbench for the NCO in `sim/nco_tb.v`. 173 | It is similar to `sim/sq_wave_gen_tb.v` in that it uses one thread to dump to fetch samples from the `NCO` and dumps them to a file called `nco_codes.txt`, and it uses another thread to set `fcw`. 174 | 175 | You can run the testbench as usual, with the provided assertions. 176 | You should also **modify the testbench** to produce a 440 Hz tone using the NCO by setting the correct `fcw`. 177 | You can use the same script to convert the sample outputs to an audio file. 178 | 179 | ```shell 180 | ../scripts/audio_from_sim sim/nco_codes.txt 181 | play output.wav 182 | ``` 183 | 184 | ### If you are on Windows 185 | You could use any python tool (recommend PyCharm) to run the script above. Then just use any media player to play the .wav file. 186 | 187 | Verify the simulated output sounds like a [pure sine tone at 440 Hz](https://www.szynalski.com/tone-generator/) rather than the harsh sound produced by a square wave generator. 188 | 189 | ### NCO on FPGA 190 | Look through `src/z1top.v` for the instantiation of the `nco`. 191 | Note that the `fcw` comes from an FSM which we will implement in the next part. 192 | Also note that `SWITCHES[0]` controls whether the square wave circuit (0) or the NCO (1) is playing through the audio jack and `SWITCHES[1]` can be used to mute the audio (0 = mute, 1 = active). 193 | 194 | For now, hard-code `fcw` to the value required to play a 440 Hz tone. 195 | ```verilog 196 | //.fcw(fcw), 197 | .fcw(24'd____), 198 | ``` 199 | 200 | Run `make impl` and `make program`, and make sure you hear a 440 Hz sine wave when you plug in headphones to the audio jack. 201 | 202 | ## Part 3: FSM + Note Sequencer (RAM) 203 | 204 | ### Sequencer RAM 205 | We want to implement a sequencer that holds 4 notes (FCWs) and plays each note for 1 second through the NCO in a loop. 206 | We have provided a RAM that's used to hold and modify these 4 notes. 207 | See `src/fcw_ram.v` for a skeleton of a RAM with 1 read/write port. 208 | Note that both read and write are *synchronous*. 209 | 210 | The RAM contains 4 24-bit values, which correspond to the FCWs for the 4 notes. 211 | Initially (upon reset) the RAM should hold these 4 notes: 212 | - 440 Hz (A4) 213 | - 494 Hz (B4) 214 | - 523 Hz (C5) 215 | - 587 Hz (D5) 216 | 217 | **Calculate** the corresponding FCWs and **edit the reset block** in `src/fcw_ram.v` with the values you calculated. 218 | 219 | ### FSM Specification 220 | With the sequencer RAM in place, we want to design and implement an FSM that will use the buttons to play, reverse-play, and pause the playback of the 4 notes in the sequencer RAM. 221 | 222 | The FSM takes the lower 3 buttons as inputs and outputs the values for 4 LEDs and the FCW for the NCO. 223 | A skeleton is provided in `src/fsm.v`. 224 | 225 | The FSM has 4 states: `REGULAR_PLAY`, `REVERSE_PLAY`, `PAUSED`, `EDIT`. 226 | Here is the state transition diagram: 227 | 228 |

229 | 230 |

231 | 232 | - The initial state should be `REGULAR_PLAY`. In this state, the FSM should play the notes in the RAM one by one (440Hz -> 494Hz -> 523Hz -> 587Hz). Each note should be played for 1 second. 233 | - Pressing the play-paused button (`button[0]`) should transition you into the `PAUSED` state from either the `REGULAR_PLAY` or `REVERSE_PLAY` states. Pressing the same button while in the `PAUSED` state should transition the FSM to the `REGULAR_PLAY` state. 234 | - In the `PAUSED` state, the RAM address should be held steady at its value before the transition into `PAUSED`, and the NCO should freeze (e.g. set `fcw` to 0). After returning to the `REGULAR_PLAY` state, the RAM address should begin incrementing again from where it left off. 235 | - You can toggle between the `REGULAR_PLAY` and `REVERSE_PLAY` states by using the reverse button (`button[1]`). In the `REVERSE_PLAY` state, you should decrement the RAM address by 1 rather than increment it by 1 every second. 236 | - The `EDIT` state can only be entered when the edit button (`button[2]`) is pressed in the `PAUSED` state. In the `EDIT` state, the current note should come out of the speaker continuously. Pressing `button[0]` will decrease the frequency of the current tone, while pressing `button[1]` should increase the frequency. (edit: and the ram should store this new fcw at the correct address). You can decide the step at will and it doesn’t have to be linear. Pressing the edit button should transition the FSM back to the `PAUSED` stage. 237 | - If the FSM is reset (`rst`) it should return to the `REGULAR_PLAY` state, and the RAM should be reset to its original values. 238 | - If you don't press any buttons, the FSM shouldn't transition to another state. 239 | - Keep in mind, when doing a reset, we cannot write the current note into the ram (what should wr_en look like?) 240 | - Make sure your note doesn't underflow or overflow beyond the min/max frequency. 241 | 242 | The `leds` output should track which note you are playing (one-hot). 243 | The `leds_state` output should represent the state your FSM is in using 2 bits. 244 | 245 | We have provided a skeleton in `src/fsm.v`. 246 | If you would like to use a different implementation, feel free to modify it. 247 | 248 | ### FSM Testbench 249 | We have provided an FSM testbench skeleton in `sim/fsm_tb.v`. 250 | 251 | You should **edit it** to simulate pressing buttons and verifying the FSM behaves correctly. 252 | Make sure you test all the state transitions. 253 | 254 | You can override `CYCLES_PER_SECOND` when instantiating `fsm` to speed up simulation (as before). 255 | 256 | ### Put Everything Together 257 | Check the top-level diagram again. 258 | Make sure that all modules are connected as desired in `src/z1top.v` (remove the `fcw` hardcoding from the previous part). 259 | 260 | **Program the FPGA**. 261 | Plug headphones into the audio out port, press the reset button, and verify that you hear the notes in the sequencer RAM play one after the other. 262 | Use the buttons to switch between different states. 263 | 264 | ## Lab Deliverables 265 | ### Lab Checkoff (due: next lab) 266 | To checkoff for this lab, have these things ready to show the TA: 267 | - Demonstrate the tunable square wave generator on the FPGA (reset, linear/exponential frequency adjustment) 268 | - Demonstrate the FSM on the FPGA (FSM with play, reverse play, pause, edit, and reset) 269 | No lab report this week! 270 | 271 | ## Acknowledgement 272 | This lab is the result of the work of many EECS151/251 GSIs over the years including: 273 | - Sp12: James Parker, Daiwei Li, Shaoyi Cheng 274 | - Sp13: Shaoyi Cheng, Vincent Lee 275 | - Fa14: Simon Scott, Ian Juch 276 | - Fa15: James Martin 277 | - Fa16: Vighnesh Iyer 278 | - Fa17: George Alexandrov, Vighnesh Iyer, Nathan Narevsky 279 | - Sp18: Arya Reais-Parsi, Taehwan Kim 280 | - Fa18: Ali Moin, George Alexandrov, Andy Zhou 281 | - Sp19: Christopher Yarp, Arya Reais-Parsi 282 | - Fa19: Vighnesh Iyer, Rebekah Zhao, Ryan Kaveh 283 | - Sp20: Tan Nguyen 284 | - Fa20: Charles Hong, Kareem Ahmad, Zhenghan Lin 285 | - Sp21: Sean Huang, Tan Nguyen 286 | - Fa21: Charles Hong, Vighnesh Iyer, Alisha Menon, Zhenghan Lin 287 | - Sp22: Alisha Menon, Yikuan Chen, Seah Kim 288 | - Fa22: Paul Kwon, Yikuan Chen 289 | --------------------------------------------------------------------------------