Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
b9b6be7cbe
|
|||
| 636b375c48 | |||
| d4d9d604b9 | |||
|
dff929de84
|
@@ -1,6 +1,15 @@
|
|||||||
|
/****
|
||||||
|
* audio_buffer.sv - holds a 2KiB audio buffer of 16-bit pcm audio
|
||||||
|
* samples (with pcm being the audio format we are using)
|
||||||
|
*
|
||||||
|
* @author: Waylon Cude, Dilanthi
|
||||||
|
* @date: 6/12/2025
|
||||||
|
*
|
||||||
|
* */
|
||||||
`ifdef VERILATOR
|
`ifdef VERILATOR
|
||||||
`include "sdvd_defs.sv"
|
`include "sdvd_defs.sv"
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
import sdvd_defs::SPEED;
|
import sdvd_defs::SPEED;
|
||||||
|
|
||||||
//this interfaces with block ram
|
//this interfaces with block ram
|
||||||
@@ -12,9 +21,6 @@ module audio_buffer(
|
|||||||
input logic play, stop,
|
input logic play, stop,
|
||||||
input SPEED speed,
|
input SPEED speed,
|
||||||
|
|
||||||
// Whether the current address being read from is in the upper or lower
|
|
||||||
// half of the 2KiB buffer
|
|
||||||
output logic address_half,
|
|
||||||
|
|
||||||
// Whether the audio buffer is currently playing
|
// Whether the audio buffer is currently playing
|
||||||
output logic playing,
|
output logic playing,
|
||||||
@@ -23,11 +29,13 @@ module audio_buffer(
|
|||||||
output logic [15:0] sample,
|
output logic [15:0] sample,
|
||||||
|
|
||||||
// Inputs for the memory buffer
|
// Inputs for the memory buffer
|
||||||
input logic [10:0] addra,
|
audio_buffer_interface.receiver driver
|
||||||
input logic [7:0] dina,
|
|
||||||
input logic clka, ena
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Whether the current address being read from is in the upper or lower
|
||||||
|
// half of the 2KiB buffer
|
||||||
|
let address_half = driver.address_half;
|
||||||
|
|
||||||
logic [9:0] address;
|
logic [9:0] address;
|
||||||
|
|
||||||
// State register
|
// State register
|
||||||
@@ -117,16 +125,16 @@ xpm_memory_sdpram #(
|
|||||||
)
|
)
|
||||||
buffer (
|
buffer (
|
||||||
.doutb(doutb), // READ_DATA_WIDTH_B-bit output: Data output for port B read operations.
|
.doutb(doutb), // READ_DATA_WIDTH_B-bit output: Data output for port B read operations.
|
||||||
.addra(addra), // ADDR_WIDTH_A-bit input: Address for port A write operations.
|
.addra(driver.addra), // ADDR_WIDTH_A-bit input: Address for port A write operations.
|
||||||
.addrb(address), // ADDR_WIDTH_B-bit input: Address for port B read operations.
|
.addrb(address), // ADDR_WIDTH_B-bit input: Address for port B read operations.
|
||||||
.clka(clka), // 1-bit input: Clock signal for port A. Also clocks port B when
|
.clka(driver.clka), // 1-bit input: Clock signal for port A. Also clocks port B when
|
||||||
// parameter CLOCKING_MODE is "common_clock".
|
// parameter CLOCKING_MODE is "common_clock".
|
||||||
|
|
||||||
.clkb(clk), // 1-bit input: Clock signal for port B when parameter CLOCKING_MODE is
|
.clkb(clk), // 1-bit input: Clock signal for port B when parameter CLOCKING_MODE is
|
||||||
// "independent_clock". Unused when parameter CLOCKING_MODE is
|
// "independent_clock". Unused when parameter CLOCKING_MODE is
|
||||||
// "common_clock".
|
// "common_clock".
|
||||||
.dina(dina), // WRITE_DATA_WIDTH_A-bit input: Data input for port A write operations.
|
.dina(driver.dina), // WRITE_DATA_WIDTH_A-bit input: Data input for port A write operations.
|
||||||
.ena(ena), // 1-bit input: Memory enable signal for port A. Must be high on clock
|
.ena(driver.ena), // 1-bit input: Memory enable signal for port A. Must be high on clock
|
||||||
// cycles when write operations are initiated. Pipelined internally.
|
// cycles when write operations are initiated. Pipelined internally.
|
||||||
|
|
||||||
.enb(enb), // 1-bit input: Memory enable signal for port B. Must be high on clock
|
.enb(enb), // 1-bit input: Memory enable signal for port B. Must be high on clock
|
||||||
@@ -135,7 +143,7 @@ buffer (
|
|||||||
.rstb(reset), // 1-bit input: Reset signal for the final port B output register stage.
|
.rstb(reset), // 1-bit input: Reset signal for the final port B output register stage.
|
||||||
// Synchronously resets output port doutb to the value specified by
|
// Synchronously resets output port doutb to the value specified by
|
||||||
// parameter READ_RESET_VALUE_B.
|
// parameter READ_RESET_VALUE_B.
|
||||||
.wea(ena) // WRITE_DATA_WIDTH_A/BYTE_WRITE_WIDTH_A-bit input: Write enable vector
|
.wea(driver.ena) // WRITE_DATA_WIDTH_A/BYTE_WRITE_WIDTH_A-bit input: Write enable vector
|
||||||
// for port A input data port dina. 1 bit wide when word-wide writes are
|
// for port A input data port dina. 1 bit wide when word-wide writes are
|
||||||
// used. In byte-wide write configurations, each bit controls the
|
// used. In byte-wide write configurations, each bit controls the
|
||||||
// writing one byte of dina to address addra. For example, to
|
// writing one byte of dina to address addra. For example, to
|
||||||
|
|||||||
+3
-2
@@ -1,8 +1,9 @@
|
|||||||
/****
|
/****
|
||||||
* pwm.sv - [must edit in future]
|
* pwm.sv - drives the pwm audio output on the FPGA given a single 16-bit
|
||||||
|
* sample.
|
||||||
*
|
*
|
||||||
* @author: Dilanthi Prentice, Waylon Cude
|
* @author: Dilanthi Prentice, Waylon Cude
|
||||||
* @date: [not sure when due yet]
|
* @date: 6-12-2025
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* */
|
* */
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
/***
|
||||||
|
* debouncer.sv - generates a debounced button press and turns it into
|
||||||
|
* a single pulse.
|
||||||
|
*
|
||||||
|
* @author: Waylon Cude, Dilanthi Prentice
|
||||||
|
* @date: 6-12-25
|
||||||
|
*
|
||||||
|
* */
|
||||||
//NOTE: you should drive this with a slow clock to actually debounce input
|
//NOTE: you should drive this with a slow clock to actually debounce input
|
||||||
module debouncer(input logic clk, input reset, input source, output logic out);
|
module debouncer(input logic clk, input reset, input source, output logic out);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
|
/****
|
||||||
|
* low_freq_clock_gen.sv - Generates different clock frequencies to drive
|
||||||
|
* different state machines and different parts of
|
||||||
|
* the design.
|
||||||
|
*
|
||||||
|
* @author: Waylon Cude, Dilanthi Prentice
|
||||||
|
* @date: 6/12/2025
|
||||||
|
* */
|
||||||
|
|
||||||
`ifdef VERILATOR
|
`ifdef VERILATOR
|
||||||
`include "sdvd_defs.sv"
|
`include "sdvd_defs.sv"
|
||||||
`endif
|
`endif
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
/***
|
||||||
|
* nexys_a7_top.sv - top level design module specific to Nexys A7100T.
|
||||||
|
*
|
||||||
|
* @author: Waylon Cude, Dilanthi Prentice
|
||||||
|
* @date: 6/12/2025
|
||||||
|
*
|
||||||
|
* **/
|
||||||
`ifdef VERILATOR
|
`ifdef VERILATOR
|
||||||
`include "sdvd_defs.sv"
|
`include "sdvd_defs.sv"
|
||||||
`endif
|
`endif
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
// A dummy sdcard module for testing the audio port
|
||||||
|
|
||||||
|
module sd(
|
||||||
|
input logic clk,
|
||||||
|
input logic reset,
|
||||||
|
output logic ready,
|
||||||
|
|
||||||
|
audio_buffer_interface.driver audio_buffer
|
||||||
|
);
|
||||||
|
|
||||||
|
// First we write 2048B into the memory buffer, then signal to play it and
|
||||||
|
// wait for half signal to avoid overwriting memory
|
||||||
|
logic initializing;
|
||||||
|
logic [16:0] rom_address;
|
||||||
|
logic [7:0] rom_data;
|
||||||
|
logic rom_enable;
|
||||||
|
// Keep track of pipeline delay so we don't write garbage into the buffer
|
||||||
|
logic delay;
|
||||||
|
|
||||||
|
// Keep track of if we are caught up to the buffer or not
|
||||||
|
logic waiting;
|
||||||
|
//TODO: This probably could be an assign, not sure
|
||||||
|
|
||||||
|
assign ready = '1;
|
||||||
|
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
if (reset) begin
|
||||||
|
delay <= 1;
|
||||||
|
rom_address <= 0;
|
||||||
|
initializing <= 1;
|
||||||
|
audio_buffer.addra <= 0;
|
||||||
|
audio_buffer.ena <= 0;
|
||||||
|
end
|
||||||
|
else if (initializing) begin
|
||||||
|
rom_enable <= 1;
|
||||||
|
case (delay)
|
||||||
|
1: delay <= 0;
|
||||||
|
0: begin
|
||||||
|
rom_address <= 1;
|
||||||
|
delay <= 0;
|
||||||
|
initializing <= 0;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
if (!waiting) begin
|
||||||
|
audio_buffer.ena <= 1;
|
||||||
|
audio_buffer.dina <= rom_data;
|
||||||
|
audio_buffer.addra <= audio_buffer.addra + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// xpm_memory_sprom: Single Port ROM
|
||||||
|
// Xilinx Parameterized Macro, version 2024.2
|
||||||
|
|
||||||
|
// The ROM has 17 address bits and 8 data bits to store 128KiB, more than
|
||||||
|
// enough for one second of 48khz audio
|
||||||
|
xpm_memory_sprom #(
|
||||||
|
.ADDR_WIDTH_A(17), // DECIMAL
|
||||||
|
.AUTO_SLEEP_TIME(0), // DECIMAL
|
||||||
|
.CASCADE_HEIGHT(0), // DECIMAL
|
||||||
|
.ECC_BIT_RANGE("7:0"), // String
|
||||||
|
.ECC_MODE("no_ecc"), // String
|
||||||
|
.ECC_TYPE("none"), // String
|
||||||
|
.IGNORE_INIT_SYNTH(0), // DECIMAL
|
||||||
|
.MEMORY_INIT_FILE("roundabout.mem"), // String
|
||||||
|
.MEMORY_INIT_PARAM("0"), // String
|
||||||
|
.MEMORY_OPTIMIZATION("true"), // String
|
||||||
|
.MEMORY_PRIMITIVE("auto"), // String
|
||||||
|
.MEMORY_SIZE(131072*8), // DECIMAL
|
||||||
|
.MESSAGE_CONTROL(0), // DECIMAL
|
||||||
|
.RAM_DECOMP("auto"), // String
|
||||||
|
.READ_DATA_WIDTH_A(8), // DECIMAL
|
||||||
|
.READ_LATENCY_A(2), // DECIMAL
|
||||||
|
.READ_RESET_VALUE_A("0"), // String
|
||||||
|
.RST_MODE_A("SYNC"), // String
|
||||||
|
.SIM_ASSERT_CHK(0), // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
|
||||||
|
.USE_MEM_INIT(1), // DECIMAL
|
||||||
|
.USE_MEM_INIT_MMI(0), // DECIMAL
|
||||||
|
.WAKEUP_TIME("disable_sleep") // String
|
||||||
|
)
|
||||||
|
xpm_memory_sprom_inst (
|
||||||
|
.douta(rom_data), // READ_DATA_WIDTH_A-bit output: Data output for port A read operations.
|
||||||
|
.addra(rom_address), // ADDR_WIDTH_A-bit input: Address for port A read operations.
|
||||||
|
.clka(clk), // 1-bit input: Clock signal for port A.
|
||||||
|
.ena(rom_enable), // 1-bit input: Memory enable signal for port A. Must be high on clock
|
||||||
|
// cycles when read operations are initiated. Pipelined internally.
|
||||||
|
|
||||||
|
.rsta(reset) // 1-bit input: Reset signal for the final port A output register stage.
|
||||||
|
// Synchronously resets output port douta to the value specified by
|
||||||
|
// parameter READ_RESET_VALUE_A.
|
||||||
|
);
|
||||||
|
|
||||||
|
// End of xpm_memory_sprom_inst instantiation
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -1,4 +1,16 @@
|
|||||||
// NOTE: This expects to be driven with a 100khz clock
|
/***
|
||||||
|
* display_anode_driver.sv - Turns on a single anode of a single digit at a time,
|
||||||
|
* rapidly rotating through all of them, generating
|
||||||
|
* a solid-looking display even though only one digit
|
||||||
|
* is on at a time.
|
||||||
|
*
|
||||||
|
* @author: Waylon Cude, Dilanthi Prentice
|
||||||
|
* @date: 6-12-2025
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
|
||||||
|
// NOTE: This expects to be driven with a 100khz clock but can be altered in
|
||||||
|
// the nexys_a7_top.sv file.
|
||||||
module display_anode_driver(
|
module display_anode_driver(
|
||||||
input logic clk,
|
input logic clk,
|
||||||
input logic reset,
|
input logic reset,
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* display_converter.sv - decodes a 5 bit digit input into its seven segment
|
* display_converter.sv - decodes a 5 bit digit input into its seven segment
|
||||||
* display equivalent using a lookup table. Display can
|
* display equivalent using a lookup table. Display can
|
||||||
* do 0 - 9, A - F, individual segmentsm and special
|
* do 0 - 9, A - F, individual segments and special
|
||||||
* characters.
|
* characters.
|
||||||
|
*
|
||||||
* @author: Dilanthi Prentice, Waylon Cude
|
* @author: Dilanthi Prentice, Waylon Cude
|
||||||
* @date: 6/12/25
|
* @date: 6/12/25
|
||||||
*
|
*
|
||||||
*
|
|
||||||
****/
|
****/
|
||||||
module display_converter(
|
module display_converter(
|
||||||
input logic [4:0] digit,
|
input logic [4:0] digit,
|
||||||
@@ -16,6 +16,7 @@ module display_converter(
|
|||||||
localparam ROM_SIZE=32;
|
localparam ROM_SIZE=32;
|
||||||
|
|
||||||
//ROM lookup table for seven segment display
|
//ROM lookup table for seven segment display
|
||||||
|
//blanks are unused space we could add characters to.
|
||||||
localparam logic [6:0] segment_rom [0:ROM_SIZE-1] = '{
|
localparam logic [6:0] segment_rom [0:ROM_SIZE-1] = '{
|
||||||
7'b1111110, //0
|
7'b1111110, //0
|
||||||
7'b0000110, //1
|
7'b0000110, //1
|
||||||
@@ -54,6 +55,7 @@ localparam logic [6:0] segment_rom [0:ROM_SIZE-1] = '{
|
|||||||
7'b0000000, //blank
|
7'b0000000, //blank
|
||||||
7'b0000000 //blank
|
7'b0000000 //blank
|
||||||
};
|
};
|
||||||
|
|
||||||
//use digit input to index segment_rom lookup table.
|
//use digit input to index segment_rom lookup table.
|
||||||
assign segment = segment_rom[digit];
|
assign segment = segment_rom[digit];
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
/***
|
/***
|
||||||
* seconds_display.sv - convert a seconds counter to a seven segement display.
|
* seconds_display.sv - converts a five bit seconds counter to its seven segement display equivalent.
|
||||||
*
|
*
|
||||||
* @author: Dilanthi Prentice, Waylon Cude
|
* @author: Dilanthi Prentice, Waylon Cude
|
||||||
* @date: 6/12/25
|
* @date: 6/12/25
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module seconds_display
|
module seconds_display
|
||||||
(
|
(
|
||||||
input [$clog2(60)-1:0] seconds,
|
input [$clog2(60)-1:0] seconds,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
### Debouncer
|
### Debouncer
|
||||||
- Logic was fundamentally wrong
|
- Logic was fundamentally wrong
|
||||||
|
- Found multiple logic bugs with testbench and then assertions
|
||||||
|
|
||||||
### Display Converter
|
### Display Converter
|
||||||
- Found a typo in a single digit
|
- Found a typo in a single digit
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
digraph rom_sd {
|
||||||
|
Reset [shape = doublecircle, label = "RESET\nbuffer_half = 0\nrom_address = 0\nrom_enable = 1\nbuf.addr=0\nready=0"];
|
||||||
|
node [shape = circle];
|
||||||
|
Delay [label="DELAY\nrom_address++"];
|
||||||
|
WriteBuf [label="WRITEBUF\nbuf.ena=1\nbuf.data=rom_data\nbuf.addr++\nrom_addr++"];
|
||||||
|
EndWrite [label="ENDWRITE\nbuf.ena=1\nbuf.data=rom_data\nbuf.addr++\nready=1"];
|
||||||
|
Wait [label = "WAIT\nbuf.ena=0"];
|
||||||
|
|
||||||
|
Reset -> Reset [label="reset"];
|
||||||
|
Reset -> Delay [label="!reset"];
|
||||||
|
|
||||||
|
Delay -> WriteBuf;
|
||||||
|
|
||||||
|
WriteBuf -> WriteBuf [label="buf.addr < 1023"]
|
||||||
|
WriteBuf -> EndWrite [label="buf.addr == 1023"]
|
||||||
|
|
||||||
|
EndWrite -> Wait;
|
||||||
|
|
||||||
|
Wait -> Wait [label = "buffer_half == buf.address_half"]
|
||||||
|
Wait -> Delay [label = "buffer_half != buf.address_half"]
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 107 KiB |
@@ -0,0 +1,18 @@
|
|||||||
|
interface audio_buffer_interface;
|
||||||
|
logic [10:0] addra;
|
||||||
|
logic [7:0] dina;
|
||||||
|
logic clka;
|
||||||
|
logic ena;
|
||||||
|
logic address_half;
|
||||||
|
|
||||||
|
modport driver (
|
||||||
|
output addra, dina, clka, ena,
|
||||||
|
input address_half
|
||||||
|
);
|
||||||
|
|
||||||
|
modport receiver (
|
||||||
|
input addra, dina, clka, ena,
|
||||||
|
output address_half
|
||||||
|
);
|
||||||
|
|
||||||
|
endinterface
|
||||||
+96000
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -1,3 +1,11 @@
|
|||||||
|
/****
|
||||||
|
* seconds_display_tb.sv - testbench for the seconds_display module.
|
||||||
|
*
|
||||||
|
* @author: Waylon Cude, Dilanthi Prentice
|
||||||
|
* @date: 6/12/2025
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
|
||||||
`timescale 1ns / 1ps
|
`timescale 1ns / 1ps
|
||||||
module seconds_display_tb;
|
module seconds_display_tb;
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user